/*      */ package com.zimbra.cs.mailbox;
/*      */ 
/*      */ import com.google.common.base.CharMatcher;
/*      */ import com.google.common.base.Objects;
/*      */ import com.google.common.base.Objects.ToStringHelper;
/*      */ import com.google.common.base.Preconditions;
/*      */ import com.google.common.base.Strings;
/*      */ import com.google.common.collect.ImmutableSet;
/*      */ import com.google.common.collect.ImmutableSet.Builder;
/*      */ import com.google.common.collect.Lists;
/*      */ import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.Builder;
/*      */ import com.zimbra.client.ZFolder;
/*      */ import com.zimbra.client.ZMailbox;
/*      */ import com.zimbra.client.ZMailbox.Options;
/*      */ import com.zimbra.common.account.Key.AccountBy;
/*      */ import com.zimbra.common.auth.ZAuthToken;
/*      */ import com.zimbra.common.calendar.ICalTimeZone;
/*      */ import com.zimbra.common.calendar.ParsedDateTime;
/*      */ import com.zimbra.common.calendar.TimeZoneMap;
/*      */ import com.zimbra.common.calendar.ZCalendar.ICalTok;
/*      */ import com.zimbra.common.calendar.ZCalendar.ZComponent;
/*      */ import com.zimbra.common.calendar.ZCalendar.ZProperty;
/*      */ import com.zimbra.common.calendar.ZCalendar.ZVCalendar;
/*      */ import com.zimbra.common.localconfig.DebugConfig;
/*      */ import com.zimbra.common.localconfig.KnownKey;
/*      */ import com.zimbra.common.localconfig.LC;
/*      */ import com.zimbra.common.mailbox.Color;
/*      */ import com.zimbra.common.mime.Rfc822ValidationInputStream;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.service.ServiceException.Argument;
/*      */ import com.zimbra.common.soap.SoapProtocol;
/*      */ import com.zimbra.common.stats.Counter;
/*      */ import com.zimbra.common.util.ArrayUtil;
/*      */ import com.zimbra.common.util.BufferStream;
/*      */ import com.zimbra.common.util.ByteUtil;
/*      */ import com.zimbra.common.util.CopyInputStream;
/*      */ import com.zimbra.common.util.DateUtil;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.Pair;
/*      */ import com.zimbra.common.util.StringUtil;
/*      */ import com.zimbra.common.util.UUIDUtil;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.account.AccessManager;
/*      */ import com.zimbra.cs.account.Account;
/*      */ import com.zimbra.cs.account.AccountServiceException;
/*      */ import com.zimbra.cs.account.AuthToken;
/*      */ import com.zimbra.cs.account.Config;
/*      */ import com.zimbra.cs.account.DataSource;
/*      */ import com.zimbra.cs.account.Domain;
/*      */ import com.zimbra.cs.account.Provisioning;
/*      */ import com.zimbra.cs.account.Server;
/*      */ import com.zimbra.cs.account.ShareLocator;
/*      */ import com.zimbra.cs.datasource.DataSourceManager;
/*      */ import com.zimbra.cs.db.DbMailItem;
/*      */ import com.zimbra.cs.db.DbMailItem.Callback;
/*      */ import com.zimbra.cs.db.DbMailItem.FolderTagCounts;
/*      */ import com.zimbra.cs.db.DbMailItem.FolderTagMap;
/*      */ import com.zimbra.cs.db.DbMailItem.QueryParams;
/*      */ import com.zimbra.cs.db.DbMailbox;
/*      */ import com.zimbra.cs.db.DbPool;
/*      */ import com.zimbra.cs.db.DbPool.DbConnection;
/*      */ import com.zimbra.cs.db.DbSession;
/*      */ import com.zimbra.cs.db.DbTag;
/*      */ import com.zimbra.cs.db.DbVolumeBlobs;
/*      */ import com.zimbra.cs.fb.FreeBusy;
/*      */ import com.zimbra.cs.fb.LocalFreeBusyProvider;
/*      */ import com.zimbra.cs.imap.ImapMessage;
/*      */ import com.zimbra.cs.index.BrowseTerm;
/*      */ import com.zimbra.cs.index.DomainBrowseTerm;
/*      */ import com.zimbra.cs.index.DomainBrowseTerm.Field;
/*      */ import com.zimbra.cs.index.IndexDocument;
/*      */ import com.zimbra.cs.index.SearchParams;
/*      */ import com.zimbra.cs.index.SortBy;
/*      */ import com.zimbra.cs.index.SortBy.Key;
/*      */ import com.zimbra.cs.index.ZimbraQuery;
/*      */ import com.zimbra.cs.iochannel.MailboxNotification;
/*      */ import com.zimbra.cs.iochannel.MessageChannel;
/*      */ import com.zimbra.cs.iochannel.MessageChannelException;
/*      */ import com.zimbra.cs.mailbox.calendar.CalendarMailSender;
/*      */ import com.zimbra.cs.mailbox.calendar.Invite;
/*      */ import com.zimbra.cs.mailbox.calendar.RecurId;
/*      */ import com.zimbra.cs.mailbox.calendar.Util;
/*      */ import com.zimbra.cs.mailbox.calendar.ZOrganizer;
/*      */ import com.zimbra.cs.mailbox.calendar.cache.CalSummaryCache;
/*      */ import com.zimbra.cs.mailbox.calendar.cache.CalSummaryCache.CalendarDataResult;
/*      */ import com.zimbra.cs.mailbox.calendar.cache.CalendarCacheManager;
/*      */ import com.zimbra.cs.mailbox.calendar.tzfixup.TimeZoneFixupRules;
/*      */ import com.zimbra.cs.mailbox.util.TypedIdList;
/*      */ import com.zimbra.cs.mime.Mime;
/*      */ import com.zimbra.cs.mime.ParsedAddress;
/*      */ import com.zimbra.cs.mime.ParsedContact;
/*      */ import com.zimbra.cs.mime.ParsedDocument;
/*      */ import com.zimbra.cs.mime.ParsedMessage;
/*      */ import com.zimbra.cs.mime.ParsedMessage.CalendarPartInfo;
/*      */ import com.zimbra.cs.mime.ParsedMessageDataSource;
/*      */ import com.zimbra.cs.mime.ParsedMessageOptions;
/*      */ import com.zimbra.cs.pop3.Pop3Message;
/*      */ import com.zimbra.cs.redolog.op.AddDocumentRevision;
/*      */ import com.zimbra.cs.redolog.op.AlterItemTag;
/*      */ import com.zimbra.cs.redolog.op.ColorItem;
/*      */ import com.zimbra.cs.redolog.op.CopyItem;
/*      */ import com.zimbra.cs.redolog.op.CreateCalendarItemPlayer;
/*      */ import com.zimbra.cs.redolog.op.CreateCalendarItemRecorder;
/*      */ import com.zimbra.cs.redolog.op.CreateChat;
/*      */ import com.zimbra.cs.redolog.op.CreateComment;
/*      */ import com.zimbra.cs.redolog.op.CreateContact;
/*      */ import com.zimbra.cs.redolog.op.CreateFolder;
/*      */ import com.zimbra.cs.redolog.op.CreateFolderPath;
/*      */ import com.zimbra.cs.redolog.op.CreateInvite;
/*      */ import com.zimbra.cs.redolog.op.CreateLink;
/*      */ import com.zimbra.cs.redolog.op.CreateMailbox;
/*      */ import com.zimbra.cs.redolog.op.CreateMessage;
/*      */ import com.zimbra.cs.redolog.op.CreateMountpoint;
/*      */ import com.zimbra.cs.redolog.op.CreateNote;
/*      */ import com.zimbra.cs.redolog.op.CreateSavedSearch;
/*      */ import com.zimbra.cs.redolog.op.CreateTag;
/*      */ import com.zimbra.cs.redolog.op.DateItem;
/*      */ import com.zimbra.cs.redolog.op.DeleteConfig;
/*      */ import com.zimbra.cs.redolog.op.DeleteItem;
/*      */ import com.zimbra.cs.redolog.op.DeleteItemFromDumpster;
/*      */ import com.zimbra.cs.redolog.op.DeleteMailbox;
/*      */ import com.zimbra.cs.redolog.op.DismissCalendarItemAlarm;
/*      */ import com.zimbra.cs.redolog.op.EditNote;
/*      */ import com.zimbra.cs.redolog.op.EnableSharedReminder;
/*      */ import com.zimbra.cs.redolog.op.FixCalendarItemEndTime;
/*      */ import com.zimbra.cs.redolog.op.FixCalendarItemPriority;
/*      */ import com.zimbra.cs.redolog.op.FixCalendarItemTZ;
/*      */ import com.zimbra.cs.redolog.op.GrantAccess;
/*      */ import com.zimbra.cs.redolog.op.ICalReply;
/*      */ import com.zimbra.cs.redolog.op.ImapCopyItem;
/*      */ import com.zimbra.cs.redolog.op.LockItem;
/*      */ import com.zimbra.cs.redolog.op.ModifyContact;
/*      */ import com.zimbra.cs.redolog.op.ModifyInvitePartStat;
/*      */ import com.zimbra.cs.redolog.op.ModifySavedSearch;
/*      */ import com.zimbra.cs.redolog.op.MoveItem;
/*      */ import com.zimbra.cs.redolog.op.PurgeImapDeleted;
/*      */ import com.zimbra.cs.redolog.op.PurgeOldMessages;
/*      */ import com.zimbra.cs.redolog.op.PurgeRevision;
/*      */ import com.zimbra.cs.redolog.op.RecoverItem;
/*      */ import com.zimbra.cs.redolog.op.RedoableOp;
/*      */ import com.zimbra.cs.redolog.op.RefreshMountpoint;
/*      */ import com.zimbra.cs.redolog.op.RenameItem;
/*      */ import com.zimbra.cs.redolog.op.RenameItemPath;
/*      */ import com.zimbra.cs.redolog.op.RenameMailbox;
/*      */ import com.zimbra.cs.redolog.op.RepositionNote;
/*      */ import com.zimbra.cs.redolog.op.RevokeAccess;
/*      */ import com.zimbra.cs.redolog.op.SaveChat;
/*      */ import com.zimbra.cs.redolog.op.SaveDocument;
/*      */ import com.zimbra.cs.redolog.op.SaveDraft;
/*      */ import com.zimbra.cs.redolog.op.SetActiveSyncDisabled;
/*      */ import com.zimbra.cs.redolog.op.SetCalendarItem;
/*      */ import com.zimbra.cs.redolog.op.SetConfig;
/*      */ import com.zimbra.cs.redolog.op.SetCustomData;
/*      */ import com.zimbra.cs.redolog.op.SetFolderDefaultView;
/*      */ import com.zimbra.cs.redolog.op.SetFolderUrl;
/*      */ import com.zimbra.cs.redolog.op.SetImapUid;
/*      */ import com.zimbra.cs.redolog.op.SetItemTags;
/*      */ import com.zimbra.cs.redolog.op.SetPermissions;
/*      */ import com.zimbra.cs.redolog.op.SetRetentionPolicy;
/*      */ import com.zimbra.cs.redolog.op.SetSubscriptionData;
/*      */ import com.zimbra.cs.redolog.op.SetWebOfflineSyncDays;
/*      */ import com.zimbra.cs.redolog.op.SnoozeCalendarItemAlarm;
/*      */ import com.zimbra.cs.redolog.op.StoreIncomingBlob;
/*      */ import com.zimbra.cs.redolog.op.TrackImap;
/*      */ import com.zimbra.cs.redolog.op.TrackSync;
/*      */ import com.zimbra.cs.redolog.op.UnlockItem;
/*      */ import com.zimbra.cs.service.AuthProvider;
/*      */ import com.zimbra.cs.service.FeedManager;
/*      */ import com.zimbra.cs.service.FeedManager.SubscriptionData;
/*      */ import com.zimbra.cs.service.util.ItemData;
/*      */ import com.zimbra.cs.service.util.ItemId;
/*      */ import com.zimbra.cs.service.util.SpamHandler;
/*      */ import com.zimbra.cs.service.util.SpamHandler.SpamReport;
/*      */ import com.zimbra.cs.session.AllAccountsRedoCommitCallback;
/*      */ import com.zimbra.cs.session.PendingModifications;
/*      */ import com.zimbra.cs.session.PendingModifications.Change;
/*      */ import com.zimbra.cs.session.PendingModifications.ModificationKey;
/*      */ import com.zimbra.cs.session.Session;
/*      */ import com.zimbra.cs.session.Session.Type;
/*      */ import com.zimbra.cs.session.SessionCache;
/*      */ import com.zimbra.cs.session.SoapSession;
/*      */ import com.zimbra.cs.session.SoapSession.DelegateSession;
/*      */ import com.zimbra.cs.stats.ZimbraPerf;
/*      */ import com.zimbra.cs.store.Blob;
/*      */ import com.zimbra.cs.store.MailboxBlob;
/*      */ import com.zimbra.cs.store.MailboxBlob.MailboxBlobInfo;
/*      */ import com.zimbra.cs.store.MailboxBlobDataSource;
/*      */ import com.zimbra.cs.store.StagedBlob;
/*      */ import com.zimbra.cs.store.StoreManager;
/*      */ import com.zimbra.cs.store.StoreManager.StoreFeature;
/*      */ import com.zimbra.cs.util.AccountUtil;
/*      */ import com.zimbra.cs.util.AccountUtil.AccountAddressMatcher;
/*      */ import com.zimbra.cs.util.SpoolingCache;
/*      */ import com.zimbra.cs.util.Zimbra;
/*      */ import com.zimbra.soap.admin.type.DataSourceType;
/*      */ import com.zimbra.soap.mail.type.CalendarItemInfo;
/*      */ import com.zimbra.soap.mail.type.Policy;
/*      */ import com.zimbra.soap.mail.type.Policy.Type;
/*      */ import com.zimbra.soap.mail.type.RetentionPolicy;
/*      */ import java.io.IOException;
/*      */ import java.io.InputStream;
/*      */ import java.io.StringWriter;
/*      */ import java.io.UnsupportedEncodingException;
/*      */ import java.io.Writer;
/*      */ import java.lang.ref.SoftReference;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Arrays;
/*      */ import java.util.Collection;
/*      */ import java.util.Collections;
/*      */ import java.util.Comparator;
/*      */ import java.util.Date;
/*      */ import java.util.EnumSet;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.LinkedHashMap;
/*      */ import java.util.LinkedList;
/*      */ import java.util.List;
/*      */ import java.util.Map;
/*      */ import java.util.Map.Entry;
/*      */ import java.util.Set;
/*      */ import java.util.UUID;
/*      */ import java.util.concurrent.ConcurrentHashMap;
/*      */ import java.util.concurrent.CopyOnWriteArrayList;
/*      */ import java.util.concurrent.TimeUnit;
/*      */ import java.util.concurrent.locks.ReentrantLock;
/*      */ import javax.mail.Address;
/*      */ import javax.mail.internet.MimeMessage;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public class Mailbox
/*      */ {
/*      */   public static final String BROWSE_BY_DOMAINS = "domains";
/*      */   public static final String BROWSE_BY_OBJECTS = "objects";
/*      */   public static final String BROWSE_BY_ATTACHMENTS = "attachments";
/*      */   public static final int ID_AUTO_INCREMENT = -1;
/*      */   public static final int ID_FOLDER_USER_ROOT = 1;
/*      */   public static final int ID_FOLDER_INBOX = 2;
/*      */   public static final int ID_FOLDER_TRASH = 3;
/*      */   public static final int ID_FOLDER_SPAM = 4;
/*      */   public static final int ID_FOLDER_SENT = 5;
/*      */   public static final int ID_FOLDER_DRAFTS = 6;
/*      */   public static final int ID_FOLDER_CONTACTS = 7;
/*      */   public static final int ID_FOLDER_TAGS = 8;
/*      */   public static final int ID_FOLDER_CONVERSATIONS = 9;
/*      */   public static final int ID_FOLDER_CALENDAR = 10;
/*      */   public static final int ID_FOLDER_ROOT = 11;
/*      */   @Deprecated
/*      */   public static final int ID_FOLDER_NOTEBOOK = 12;
/*      */   public static final int ID_FOLDER_AUTO_CONTACTS = 13;
/*      */   public static final int ID_FOLDER_IM_LOGS = 14;
/*      */   public static final int ID_FOLDER_TASKS = 15;
/*      */   public static final int ID_FOLDER_BRIEFCASE = 16;
/*      */   public static final int ID_FOLDER_COMMENTS = 17;
/*      */   @Deprecated
/*      */   public static final int ID_FOLDER_PROFILE = 18;
/*      */   public static final int HIGHEST_SYSTEM_ID = 18;
/*      */   public static final int FIRST_USER_ID = 256;
/*      */   public static final String CONF_PREVIOUS_MAILBOX_IDS = "prev_mbox_ids";
/*      */   public final MailboxIndex index;
/*      */   public final MailboxLock lock;
/*      */   
/*      */   public static final class MailboxData
/*      */     implements Cloneable
/*      */   {
/*      */     public int id;
/*      */     public int schemaGroupId;
/*      */     public String accountId;
/*      */     public long size;
/*      */     public int contacts;
/*      */     public short indexVolumeId;
/*      */     public int lastBackupDate;
/*      */     public int lastItemId;
/*      */     public int lastChangeId;
/*      */     public long lastChangeDate;
/*      */     public int lastWriteDate;
/*      */     public int recentMessages;
/*      */     public int trackSync;
/*      */     public boolean trackImap;
/*      */     public Set<String> configKeys;
/*      */     public MailboxVersion version;
/*      */     public int itemcacheCheckpoint;
/*      */     
/*      */     protected MailboxData clone()
/*      */     {
/*  306 */       MailboxData mbd = new MailboxData();
/*  307 */       mbd.id = this.id;
/*  308 */       mbd.schemaGroupId = this.schemaGroupId;
/*  309 */       mbd.accountId = this.accountId;
/*  310 */       mbd.size = this.size;
/*  311 */       mbd.contacts = this.contacts;
/*  312 */       mbd.indexVolumeId = this.indexVolumeId;
/*  313 */       mbd.lastItemId = this.lastItemId;
/*  314 */       mbd.lastChangeId = this.lastChangeId;
/*  315 */       mbd.lastChangeDate = this.lastChangeDate;
/*  316 */       mbd.lastWriteDate = this.lastWriteDate;
/*  317 */       mbd.recentMessages = this.recentMessages;
/*  318 */       mbd.trackSync = this.trackSync;
/*  319 */       mbd.trackImap = this.trackImap;
/*  320 */       if (this.configKeys != null) {
/*  321 */         mbd.configKeys = new HashSet(this.configKeys);
/*      */       }
/*  323 */       mbd.version = this.version;
/*  324 */       mbd.itemcacheCheckpoint = this.itemcacheCheckpoint;
/*  325 */       return mbd;
/*      */     }
/*      */   }
/*      */   
/*      */   static final class IndexItemEntry {
/*      */     final List<IndexDocument> documents;
/*      */     final MailItem item;
/*      */     
/*      */     IndexItemEntry(MailItem item, List<IndexDocument> docs) {
/*  334 */       this.item = item;
/*  335 */       this.documents = docs;
/*      */     }
/*      */     
/*      */     public String toString()
/*      */     {
/*  340 */       return Objects.toStringHelper(this).add("id", this.item.getId()).toString();
/*      */     }
/*      */   }
/*      */   
/*      */   private final class MailboxChange
/*      */   {
/*      */     private static final int NO_CHANGE = -1;
/*  347 */     long timestamp = System.currentTimeMillis();
/*  348 */     int depth = 0;
/*      */     boolean active;
/*  350 */     DbPool.DbConnection conn = null;
/*  351 */     RedoableOp recorder = null;
/*  352 */     List<Mailbox.IndexItemEntry> indexItems = new ArrayList();
/*  353 */     Mailbox.ItemCache itemCache = null;
/*  354 */     OperationContext octxt = null;
/*  355 */     MailItem.TargetConstraint tcon = null;
/*      */     
/*  357 */     Integer sync = null;
/*  358 */     Boolean imap = null;
/*  359 */     long size = -1L;
/*  360 */     int itemId = -1;
/*  361 */     int changeId = -1;
/*  362 */     int contacts = -1;
/*  363 */     int accessed = -1;
/*  364 */     int recent = -1;
/*  365 */     Pair<String, Metadata> config = null;
/*      */     
/*  367 */     PendingModifications dirty = new PendingModifications();
/*  368 */     final List<Object> otherDirtyStuff = new LinkedList();
/*  369 */     MailItem.PendingDelete deletes = null;
/*      */     private boolean writeChange;
/*      */     
/*      */     MailboxChange() {}
/*      */     
/*      */     MailboxOperation getOperation()
/*      */     {
/*  376 */       if (this.recorder != null) {
/*  377 */         return this.recorder.getOperation();
/*      */       }
/*  379 */       return null;
/*      */     }
/*      */     
/*      */     void setTimestamp(long millis) {
/*  383 */       if (this.depth == 1) {
/*  384 */         this.timestamp = millis;
/*      */       }
/*      */     }
/*      */     
/*      */     void startChange(String caller, OperationContext ctxt, RedoableOp op, boolean write) {
/*  389 */       this.active = true;
/*  390 */       if (this.depth++ == 0) {
/*  391 */         this.octxt = ctxt;
/*  392 */         this.recorder = op;
/*  393 */         this.writeChange = write;
/*  394 */         ZimbraLog.mailbox.debug("beginning operation: %s", new Object[] { caller });
/*      */       } else {
/*  396 */         assert ((!write) || (this.writeChange));
/*      */         
/*      */ 
/*  399 */         ZimbraLog.mailbox.debug("  increasing stack depth to %d (%s)", new Object[] { Integer.valueOf(this.depth), caller });
/*      */       }
/*      */     }
/*      */     
/*      */     boolean endChange() {
/*  404 */       if (ZimbraLog.mailbox.isDebugEnabled()) {
/*  405 */         if (this.depth <= 1) {
/*  406 */           ZimbraLog.mailbox.debug("ending operation %s", new Object[] { this.recorder == null ? "" : this.recorder.getClass().getSimpleName() });
/*      */         }
/*      */         else {
/*  409 */           ZimbraLog.mailbox.debug("  decreasing stack depth to %d", new Object[] { Integer.valueOf(this.depth - 1) });
/*      */         }
/*      */       }
/*  412 */       return --this.depth == 0;
/*      */     }
/*      */     
/*      */     boolean isActive() {
/*  416 */       return this.active;
/*      */     }
/*      */     
/*      */     DbPool.DbConnection getConnection() throws ServiceException {
/*  420 */       if (this.conn == null) {
/*  421 */         this.conn = DbPool.getConnection(Mailbox.this);
/*  422 */         ZimbraLog.mailbox.debug("  fetching new DB connection");
/*      */       }
/*  424 */       return this.conn;
/*      */     }
/*      */     
/*      */     RedoableOp getRedoPlayer() {
/*  428 */       return this.octxt == null ? null : this.octxt.getPlayer();
/*      */     }
/*      */     
/*      */     RedoableOp getRedoRecorder() {
/*  432 */       return this.recorder;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     void addIndexItem(Mailbox.IndexItemEntry item)
/*      */     {
/*  439 */       this.indexItems.add(item);
/*      */     }
/*      */     
/*      */     void addPendingDelete(MailItem.PendingDelete info) {
/*  443 */       if (this.deletes == null) {
/*  444 */         this.deletes = info;
/*      */       } else {
/*  446 */         this.deletes.add(info);
/*      */       }
/*      */     }
/*      */     
/*      */     boolean isMailboxRowDirty(Mailbox.MailboxData data) {
/*  451 */       if ((this.recent != -1) || (this.size != -1L) || (this.contacts != -1)) {
/*  452 */         return true;
/*      */       }
/*  454 */       if ((this.itemId != -1) && (this.itemId / DbMailbox.ITEM_CHECKPOINT_INCREMENT > data.lastItemId / DbMailbox.ITEM_CHECKPOINT_INCREMENT)) {
/*  455 */         return true;
/*      */       }
/*  457 */       if ((this.changeId != -1) && (this.changeId / DbMailbox.CHANGE_CHECKPOINT_INCREMENT > data.lastChangeId / DbMailbox.CHANGE_CHECKPOINT_INCREMENT)) {
/*  458 */         return true;
/*      */       }
/*  460 */       return false;
/*      */     }
/*      */     
/*      */     void reset() {
/*  464 */       DbPool.quietClose(this.conn);
/*  465 */       this.active = false;
/*  466 */       this.conn = null;
/*  467 */       this.octxt = null;
/*  468 */       this.tcon = null;
/*  469 */       this.imap = null;
/*  470 */       this.depth = 0;
/*  471 */       this.size = -1L;
/*  472 */       this.changeId = -1;
/*  473 */       this.itemId = -1;
/*  474 */       this.contacts = -1;
/*  475 */       this.accessed = -1;
/*  476 */       this.recent = -1;
/*  477 */       this.sync = null;
/*  478 */       this.config = null;
/*  479 */       this.deletes = null;
/*  480 */       this.itemCache = null;
/*  481 */       this.indexItems.clear();
/*  482 */       this.dirty.clear();
/*  483 */       this.otherDirtyStuff.clear();
/*  484 */       Mailbox.this.threadChange.remove();
/*      */       
/*  486 */       ZimbraLog.mailbox.debug("clearing change");
/*      */     }
/*      */     
/*      */     boolean hasChanges() {
/*  490 */       if (this.sync != null)
/*  491 */         return true;
/*  492 */       if (this.imap != null)
/*  493 */         return true;
/*  494 */       if (this.size != -1L)
/*  495 */         return true;
/*  496 */       if (this.itemId != -1)
/*  497 */         return true;
/*  498 */       if (this.contacts != -1)
/*  499 */         return true;
/*  500 */       if (this.changeId != -1)
/*  501 */         return true;
/*  502 */       if (this.accessed != -1)
/*  503 */         return true;
/*  504 */       if (this.recent != -1)
/*  505 */         return true;
/*  506 */       if (this.config != null)
/*  507 */         return true;
/*  508 */       if (this.deletes != null) {
/*  509 */         return true;
/*      */       }
/*  511 */       return false;
/*      */     }
/*      */   }
/*      */   
/*      */   private static class FolderCache
/*      */   {
/*      */     private final Map<Integer, Folder> mapById;
/*      */     private final Map<String, Folder> mapByUuid;
/*      */     
/*      */     public FolderCache() {
/*  521 */       this.mapById = new ConcurrentHashMap();
/*  522 */       this.mapByUuid = new ConcurrentHashMap();
/*      */     }
/*      */     
/*      */     public void put(Folder folder) {
/*  526 */       this.mapById.put(Integer.valueOf(folder.getId()), folder);
/*  527 */       if (folder.getUuid() != null) {
/*  528 */         this.mapByUuid.put(folder.getUuid(), folder);
/*      */       }
/*      */     }
/*      */     
/*      */     public Folder get(int id) {
/*  533 */       return (Folder)this.mapById.get(Integer.valueOf(id));
/*      */     }
/*      */     
/*      */     public Folder get(String uuid) {
/*  537 */       return (Folder)this.mapByUuid.get(uuid);
/*      */     }
/*      */     
/*      */     public void remove(Folder folder) {
/*  541 */       Folder removed = (Folder)this.mapById.remove(Integer.valueOf(folder.getId()));
/*  542 */       if (removed != null) {
/*  543 */         String uuid = removed.getUuid();
/*  544 */         if (uuid != null) {
/*  545 */           this.mapByUuid.remove(uuid);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */     public Collection<Folder> values() {
/*  551 */       return this.mapById.values();
/*      */     }
/*      */     
/*      */     public int size() {
/*  555 */       return this.mapById.size();
/*      */     }
/*      */     
/*      */     public FolderCache makeCopy() throws ServiceException {
/*  559 */       FolderCache copy = new FolderCache();
/*  560 */       for (Folder folder : values()) {
/*  561 */         MailItem.UnderlyingData data = folder.getUnderlyingData().clone();
/*  562 */         data.setFlag(Flag.FlagInfo.UNCACHED);
/*  563 */         data.metadata = folder.encodeMetadata().toString();
/*  564 */         copy.put((Folder)MailItem.constructItem(folder.getMailbox(), data));
/*      */       }
/*  566 */       for (Folder folder : copy.values()) {
/*  567 */         Folder parent = copy.get(folder.getFolderId());
/*  568 */         if (parent != null) {
/*  569 */           parent.addChild(folder, false);
/*      */         }
/*      */       }
/*  572 */       return copy;
/*      */     }
/*      */   }
/*      */   
/*      */   private static class ItemCache {
/*      */     private final Map<Integer, MailItem> mapById;
/*      */     private final Map<String, Integer> uuid2id;
/*      */     private final Mailbox mbox;
/*  580 */     private boolean isAlwaysOn = false;
/*      */     
/*      */     public ItemCache(Mailbox mbox) {
/*  583 */       this.mapById = new ConcurrentLinkedHashMap.Builder().maximumWeightedCapacity(Mailbox.MAX_ITEM_CACHE_WITH_LISTENERS).build();
/*      */       
/*  585 */       this.uuid2id = new ConcurrentHashMap(Mailbox.MAX_ITEM_CACHE_WITH_LISTENERS);
/*  586 */       this.mbox = mbox;
/*  587 */       this.isAlwaysOn = Zimbra.isAlwaysOn();
/*      */     }
/*      */     
/*      */     public void put(MailItem item) {
/*  591 */       if (this.isAlwaysOn) {
/*      */         try {
/*  593 */           MemcachedItemCache.getInstance().put(this.mbox, item);
/*      */         } catch (ServiceException e) {
/*  595 */           ZimbraLog.mailbox.error("error while writing item to cache", e);
/*      */         }
/*      */       } else {
/*  598 */         int id = item.getId();
/*  599 */         this.mapById.put(Integer.valueOf(id), item);
/*  600 */         String uuid = item.getUuid();
/*  601 */         if (uuid != null) {
/*  602 */           this.uuid2id.put(uuid, Integer.valueOf(id));
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */     public MailItem get(int id) {
/*  608 */       if (this.isAlwaysOn) {
/*  609 */         MailItem item = null;
/*      */         try {
/*  611 */           item = MemcachedItemCache.getInstance().get(this.mbox, id);
/*      */         } catch (ServiceException e) {
/*  613 */           ZimbraLog.mailbox.error("error while fetching item from cache", e);
/*      */         }
/*  615 */         return item;
/*      */       }
/*  617 */       return (MailItem)this.mapById.get(Integer.valueOf(id));
/*      */     }
/*      */     
/*      */     public MailItem get(String uuid)
/*      */     {
/*  622 */       if (this.isAlwaysOn) {
/*  623 */         MailItem item = null;
/*      */         try {
/*  625 */           item = MemcachedItemCache.getInstance().get(this.mbox, uuid);
/*      */         } catch (ServiceException e) {
/*  627 */           ZimbraLog.mailbox.error("error while fetching item from cache", e);
/*      */         }
/*  629 */         return item;
/*      */       }
/*      */       
/*  632 */       Integer id = (Integer)this.uuid2id.get(uuid);
/*  633 */       return id != null ? (MailItem)this.mapById.get(id) : null;
/*      */     }
/*      */     
/*      */     public MailItem remove(MailItem item)
/*      */     {
/*  638 */       return remove(item.getId());
/*      */     }
/*      */     
/*      */     public MailItem remove(int id) {
/*  642 */       if (this.isAlwaysOn) {
/*  643 */         MailItem removed = null;
/*      */         try {
/*  645 */           removed = MemcachedItemCache.getInstance().remove(this.mbox, id);
/*      */         } catch (ServiceException e) {
/*  647 */           ZimbraLog.mailbox.error("error while removing item from cache", e);
/*      */         }
/*  649 */         return removed;
/*      */       }
/*  651 */       MailItem removed = (MailItem)this.mapById.remove(Integer.valueOf(id));
/*  652 */       if (removed != null) {
/*  653 */         String uuid = removed.getUuid();
/*  654 */         if (uuid != null) {
/*  655 */           this.uuid2id.remove(uuid);
/*      */         }
/*      */       }
/*  658 */       return removed;
/*      */     }
/*      */     
/*      */     public boolean contains(MailItem item)
/*      */     {
/*  663 */       if (this.isAlwaysOn) {
/*      */         try {
/*  665 */           return MemcachedItemCache.getInstance().get(this.mbox, item.getId()) != null;
/*      */         } catch (ServiceException e) {
/*  667 */           ZimbraLog.mailbox.error("error while checking item cache", e);
/*  668 */           return false;
/*      */         }
/*      */       }
/*  671 */       return this.mapById.containsKey(Integer.valueOf(item.getId()));
/*      */     }
/*      */     
/*      */     public Collection<MailItem> values()
/*      */     {
/*  676 */       if (this.isAlwaysOn)
/*      */       {
/*  678 */         return Collections.emptyList();
/*      */       }
/*  680 */       return this.mapById.values();
/*      */     }
/*      */     
/*      */     public int size()
/*      */     {
/*  685 */       if (this.isAlwaysOn) {
/*  686 */         return 0;
/*      */       }
/*  688 */       return this.mapById.size();
/*      */     }
/*      */     
/*      */     public void clear()
/*      */     {
/*  693 */       this.mapById.clear();
/*  694 */       this.uuid2id.clear();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  707 */   private final ReentrantLock emptyFolderOpLock = new ReentrantLock();
/*      */   
/*      */ 
/*  710 */   private static final int MAX_ITEM_CACHE_WITH_LISTENERS = LC.zimbra_mailbox_active_cache.intValue();
/*  711 */   private static final int MAX_ITEM_CACHE_WITHOUT_LISTENERS = LC.zimbra_mailbox_inactive_cache.intValue();
/*  712 */   private static final int MAX_ITEM_CACHE_FOR_GALSYNC_MAILBOX = LC.zimbra_mailbox_galsync_cache.intValue();
/*      */   
/*      */   private static final int MAX_MSGID_CACHE = 10;
/*      */   private final int mId;
/*      */   private MailboxData mData;
/*  717 */   private final ThreadLocal<MailboxChange> threadChange = new ThreadLocal();
/*  718 */   private final List<Session> mListeners = new CopyOnWriteArrayList();
/*      */   
/*      */   private FolderCache mFolderCache;
/*      */   private Map<Object, Tag> mTagCache;
/*  722 */   private SoftReference<ItemCache> mItemCache = new SoftReference(null);
/*  723 */   private final Map<String, Integer> mConvHashes = new ConcurrentLinkedHashMap.Builder().maximumWeightedCapacity(10L).build();
/*      */   
/*  725 */   private final Map<String, Integer> mSentMessageIDs = new ConcurrentLinkedHashMap.Builder().maximumWeightedCapacity(10L).build();
/*      */   
/*      */   private MailboxMaintenance maintenance;
/*      */   
/*  729 */   private volatile boolean open = false;
/*  730 */   private boolean galSyncMailbox = false;
/*  731 */   private volatile boolean requiresWriteLock = true;
/*      */   
/*      */   protected Mailbox(MailboxData data) {
/*  734 */     this.mId = data.id;
/*  735 */     this.mData = data;
/*  736 */     this.mData.lastChangeDate = System.currentTimeMillis();
/*  737 */     this.index = new MailboxIndex(this);
/*      */     
/*      */ 
/*  740 */     this.lock = new MailboxLock(data.accountId, this);
/*      */   }
/*      */   
/*      */   public void setGalSyncMailbox(boolean galSyncMailbox) {
/*  744 */     this.galSyncMailbox = galSyncMailbox;
/*      */   }
/*      */   
/*      */   public boolean isGalSyncMailbox() {
/*  748 */     return this.galSyncMailbox;
/*      */   }
/*      */   
/*      */   boolean isOpen() {
/*  752 */     return this.open;
/*      */   }
/*      */   
/*      */   private MailboxChange currentChange() {
/*  756 */     MailboxChange change = (MailboxChange)this.threadChange.get();
/*  757 */     if (change == null) {
/*  758 */       change = new MailboxChange();
/*  759 */       this.threadChange.set(change);
/*      */     }
/*  761 */     return change;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean requiresWriteLock()
/*      */   {
/*  769 */     return (this.requiresWriteLock) || (Zimbra.isAlwaysOn()) || (!LC.zimbra_mailbox_lock_readwrite.booleanValue());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean open()
/*      */     throws ServiceException
/*      */   {
/*  784 */     if (this.open) {
/*  785 */       return false;
/*      */     }
/*      */     
/*  788 */     this.lock.lock();
/*      */     try {
/*  790 */       if (this.open) {
/*  791 */         return false;
/*      */       }
/*      */       
/*  794 */       this.index.open();
/*      */       Metadata md;
/*  796 */       if (this.mData.version == null)
/*      */       {
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  803 */         md = getConfig(null, "ver");
/*  804 */         this.mData.version = MailboxVersion.fromMetadata(md);
/*      */       }
/*      */       
/*      */ 
/*  808 */       if (this.mData.version.tooHigh()) {
/*  809 */         throw ServiceException.FAILURE("invalid mailbox version: " + this.mData.version + " (too high)", null);
/*      */       }
/*      */       
/*  812 */       if (!this.mData.version.atLeast(MailboxVersion.CURRENT)) {
/*  813 */         if (!this.mData.version.atLeast(1, 2)) {
/*  814 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 1.2", new Object[] { getVersion() });
/*  815 */           this.index.upgradeMailboxTo1_2();
/*      */         }
/*      */         
/*      */ 
/*  819 */         if (!this.mData.version.atLeast(1, 4)) {
/*  820 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 1.4", new Object[] { getVersion() });
/*  821 */           recalculateFolderAndTagCounts();
/*  822 */           updateVersion(new MailboxVersion((short)1, (short)4));
/*      */         }
/*      */         
/*  825 */         if (!this.mData.version.atLeast(1, 5)) {
/*  826 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 1.5", new Object[] { getVersion() });
/*  827 */           this.index.indexAllDeferredFlagItems();
/*      */         }
/*      */         
/*      */ 
/*  831 */         if (!this.mData.version.atLeast(1, 7)) {
/*  832 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 1.7", new Object[] { getVersion() });
/*  833 */           MailboxUpgrade.upgradeTo1_7(this);
/*  834 */           updateVersion(new MailboxVersion((short)1, (short)7));
/*      */         }
/*      */         
/*      */ 
/*  838 */         if (!this.mData.version.atLeast(1, 8)) {
/*  839 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 1.8", new Object[] { getVersion() });
/*  840 */           MailboxUpgrade.upgradeTo1_8(this);
/*  841 */           updateVersion(new MailboxVersion((short)1, (short)8));
/*      */         }
/*      */         
/*      */ 
/*  845 */         if (!this.mData.version.atLeast(1, 9)) {
/*  846 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 1.9", new Object[] { getVersion() });
/*  847 */           purgeImapDeleted(null);
/*  848 */           updateVersion(new MailboxVersion((short)1, (short)9));
/*      */         }
/*      */         
/*      */ 
/*  852 */         if (!this.mData.version.atLeast(1, 10)) {
/*  853 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 1.10", new Object[] { getVersion() });
/*      */           
/*      */ 
/*      */ 
/*  857 */           updateVersion(new MailboxVersion((short)1, (short)10));
/*  858 */           migrateWikiFolders();
/*      */         }
/*      */         
/*  861 */         if (!this.mData.version.atLeast(2, 0)) {
/*  862 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 2.0", new Object[] { getVersion() });
/*  863 */           MailboxUpgrade.upgradeTo2_0(this);
/*  864 */           updateVersion(new MailboxVersion((short)2, (short)0));
/*      */         }
/*      */         
/*      */ 
/*  868 */         if (!this.mData.version.atLeast(2, 1)) {
/*  869 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 2.1", new Object[] { getVersion() });
/*  870 */           MailboxUpgrade.upgradeTo2_1(this);
/*  871 */           updateVersion(new MailboxVersion((short)2, (short)1));
/*      */         }
/*      */         
/*      */ 
/*  875 */         if (!this.mData.version.atLeast(2, 2)) {
/*  876 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 2.2", new Object[] { getVersion() });
/*      */           
/*  878 */           updateVersion(new MailboxVersion((short)2, (short)2));
/*      */         }
/*      */         
/*      */ 
/*  882 */         if (!this.mData.version.atLeast(2, 3)) {
/*  883 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 2.3", new Object[] { getVersion() });
/*  884 */           MailboxUpgrade.upgradeTo2_3(this);
/*  885 */           updateVersion(new MailboxVersion((short)2, (short)3));
/*      */         }
/*      */         
/*      */ 
/*  889 */         if (!this.mData.version.atLeast(2, 4)) {
/*  890 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 2.4", new Object[] { getVersion() });
/*  891 */           MailboxUpgrade.upgradeTo2_4(this);
/*  892 */           updateVersion(new MailboxVersion((short)2, (short)4));
/*      */         }
/*      */         
/*      */ 
/*  896 */         if (!this.mData.version.atLeast(2, 5)) {
/*  897 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 2.5", new Object[] { getVersion() });
/*  898 */           MailboxUpgrade.upgradeTo2_5(this);
/*  899 */           updateVersion(new MailboxVersion((short)2, (short)5));
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*  905 */         if (!this.mData.version.atLeast(2, 7)) {
/*  906 */           ZimbraLog.mailbox.info("Upgrade mailbox from %s to 2.7", new Object[] { getVersion() });
/*  907 */           MailboxUpgrade.upgradeTo2_7(this);
/*  908 */           updateVersion(new MailboxVersion((short)2, (short)7));
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*  913 */       return this.open = 1;
/*      */     } finally {
/*  915 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public int getId()
/*      */   {
/*  923 */     return this.mId;
/*      */   }
/*      */   
/*      */   public int getSchemaGroupId()
/*      */   {
/*  928 */     return this.mData.schemaGroupId;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public String getAccountId()
/*      */   {
/*  935 */     return this.mData.accountId;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public Account getAccount()
/*      */     throws ServiceException
/*      */   {
/*  943 */     String accountId = getAccountId();
/*  944 */     Account acct = Provisioning.getInstance().get(Key.AccountBy.id, accountId);
/*  945 */     if (acct == null) {
/*  946 */       ZimbraLog.mailbox.warn("no account found in directory for mailbox %d (was expecting %s)", new Object[] { Integer.valueOf(this.mId), accountId });
/*  947 */       throw AccountServiceException.NO_SUCH_ACCOUNT(accountId);
/*      */     }
/*  949 */     return acct;
/*      */   }
/*      */   
/*      */   public short getIndexVolume()
/*      */   {
/*  954 */     return this.mData.indexVolumeId;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MailboxMaintenance getMaintenance()
/*      */   {
/*  961 */     return this.maintenance;
/*      */   }
/*      */   
/*      */   public MailSender getMailSender()
/*      */     throws ServiceException
/*      */   {
/*  967 */     MailSender sender = new MailSender();
/*  968 */     sender.setTrackBadHosts(true);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*  973 */     sender.setSession(getAccount());
/*      */     
/*  975 */     return sender;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public List<Session> getListeners(Session.Type stype)
/*      */   {
/*  982 */     if (this.mListeners.isEmpty())
/*  983 */       return Collections.emptyList();
/*  984 */     if (stype == null) {
/*  985 */       return new ArrayList(this.mListeners);
/*      */     }
/*      */     
/*  988 */     List<Session> sessions = new ArrayList(this.mListeners.size());
/*  989 */     for (Session s : this.mListeners) {
/*  990 */       if (s.getType() == stype) {
/*  991 */         sessions.add(s);
/*      */       }
/*      */     }
/*  994 */     return sessions;
/*      */   }
/*      */   
/*      */   boolean hasListeners(Session.Type stype) {
/*  998 */     if (this.mListeners.isEmpty())
/*  999 */       return false;
/* 1000 */     if (stype == null) {
/* 1001 */       return true;
/*      */     }
/*      */     
/* 1004 */     for (Session s : this.mListeners) {
/* 1005 */       if (s.getType() == stype) {
/* 1006 */         return true;
/*      */       }
/*      */     }
/* 1009 */     return false;
/*      */   }
/*      */   
/*      */   public Session getListener(String sessionId)
/*      */   {
/* 1014 */     if (sessionId != null) {
/* 1015 */       for (Session session : this.mListeners) {
/* 1016 */         if (sessionId.equals(session.getSessionId())) {
/* 1017 */           return session;
/*      */         }
/*      */       }
/*      */     }
/* 1021 */     return null;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public void addListener(Session session)
/*      */     throws ServiceException
/*      */   {
/* 1030 */     if (session == null) {
/* 1031 */       return;
/*      */     }
/* 1033 */     assert (session.getSessionId() != null);
/* 1034 */     this.lock.lock();
/*      */     try {
/* 1036 */       if (this.maintenance != null) {
/* 1037 */         throw MailServiceException.MAINTENANCE(this.mId);
/*      */       }
/* 1039 */       if (!this.mListeners.contains(session)) {
/* 1040 */         this.mListeners.add(session);
/*      */       }
/*      */       
/* 1043 */       if ((Zimbra.isAlwaysOn()) && 
/* 1044 */         (this.mListeners.size() == 1))
/*      */       {
/* 1046 */         DbPool.DbConnection conn = DbPool.getConnection();
/*      */         try {
/* 1048 */           DbSession.create(conn, session.getMailbox().getId(), Provisioning.getInstance().getLocalServer().getId());
/*      */           
/* 1050 */           conn.commit();
/*      */         } catch (ServiceException e) {
/* 1052 */           ZimbraLog.session.info("exception while inserting session into DB", e);
/*      */         } finally {
/* 1054 */           if (conn != null) {
/* 1055 */             conn.closeQuietly();
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     finally
/*      */     {
/* 1062 */       this.lock.release();
/*      */     }
/*      */     
/* 1065 */     ZimbraLog.mailbox.debug("adding listener: %s", new Object[] { session });
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public void removeListener(Session session)
/*      */   {
/* 1073 */     this.lock.lock();
/* 1074 */     this.mListeners.remove(session);
/*      */     try
/*      */     {
/* 1077 */       if ((Zimbra.isAlwaysOn()) && 
/* 1078 */         (this.mListeners.size() == 0))
/*      */       {
/* 1080 */         DbPool.DbConnection conn = null;
/*      */         try {
/* 1082 */           conn = DbPool.getConnection();
/* 1083 */           DbSession.delete(conn, getId(), Provisioning.getInstance().getLocalServer().getId());
/* 1084 */           conn.commit();
/*      */         } catch (ServiceException e) {
/* 1086 */           ZimbraLog.mailbox.error("Deleting database session: ", e);
/*      */         } finally {
/* 1088 */           if (conn != null) {
/* 1089 */             conn.closeQuietly();
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     finally {
/* 1095 */       this.lock.release();
/*      */     }
/*      */     
/* 1098 */     if (ZimbraLog.mailbox.isDebugEnabled()) {
/* 1099 */       ZimbraLog.mailbox.debug("clearing listener: " + session);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   private void purgeListeners()
/*      */   {
/* 1108 */     ZimbraLog.mailbox.debug("purging listeners");
/*      */     
/* 1110 */     for (Session session : this.mListeners) {
/* 1111 */       SessionCache.clearSession(session);
/*      */     }
/*      */     
/*      */ 
/* 1115 */     this.mListeners.clear();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean isTrackingSync()
/*      */   {
/* 1124 */     return getSyncCutoff() > 0;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getSyncCutoff()
/*      */   {
/* 1132 */     return currentChange().sync == null ? this.mData.trackSync : currentChange().sync.intValue();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean isTrackingImap()
/*      */   {
/* 1140 */     return currentChange().imap == null ? this.mData.trackImap : currentChange().imap.booleanValue();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getOperationTimestamp()
/*      */   {
/* 1148 */     return (int)(currentChange().timestamp / 1000L);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public long getOperationTimestampMillis()
/*      */   {
/* 1156 */     return currentChange().timestamp;
/*      */   }
/*      */   
/*      */ 
/*      */   public long getLastChangeDate()
/*      */   {
/* 1162 */     return this.mData.lastChangeDate;
/*      */   }
/*      */   
/*      */   public int getItemcacheCheckpoint() {
/* 1166 */     return this.mData.itemcacheCheckpoint;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getLastChangeID()
/*      */   {
/* 1177 */     return currentChange().changeId == -1 ? this.mData.lastChangeId : Math.max(this.mData.lastChangeId, currentChange().changeId);
/*      */   }
/*      */   
/*      */   private void setOperationChangeID(int changeFromRedo) throws ServiceException
/*      */   {
/* 1182 */     if (currentChange().changeId != -1) {
/* 1183 */       if (currentChange().changeId == changeFromRedo) {
/* 1184 */         return;
/*      */       }
/* 1186 */       throw ServiceException.FAILURE("cannot specify change ID after change is in progress", null);
/*      */     }
/*      */     
/* 1189 */     int lastId = getLastChangeID();
/* 1190 */     int nextId = changeFromRedo == -1 ? lastId + 1 : changeFromRedo;
/*      */     
/*      */ 
/* 1193 */     currentChange().changeId = nextId;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getOperationChangeID()
/*      */     throws ServiceException
/*      */   {
/* 1208 */     if (currentChange().changeId == -1) {
/* 1209 */       setOperationChangeID(-1);
/*      */     }
/* 1211 */     return currentChange().changeId;
/*      */   }
/*      */   
/*      */   boolean checkItemChangeID(MailItem item) throws ServiceException
/*      */   {
/* 1216 */     if (item == null) {
/* 1217 */       return true;
/*      */     }
/* 1219 */     return checkItemChangeID(item.getModifiedSequence(), item.getSavedSequence());
/*      */   }
/*      */   
/*      */   public boolean checkItemChangeID(int modMetadata, int modContent) throws ServiceException {
/* 1223 */     if ((currentChange().octxt == null) || (currentChange().octxt.change < 0)) {
/* 1224 */       return true;
/*      */     }
/* 1226 */     OperationContext octxt = currentChange().octxt;
/* 1227 */     if ((!octxt.changetype) && (modContent > octxt.change))
/* 1228 */       return false;
/* 1229 */     if ((octxt.changetype == true) && (modMetadata > octxt.change)) {
/* 1230 */       throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */     }
/* 1232 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getLastItemId()
/*      */   {
/* 1242 */     return currentChange().itemId == -1 ? this.mData.lastItemId : currentChange().itemId;
/*      */   }
/*      */   
/*      */ 
/*      */   private int getNextItemId(int idFromRedo)
/*      */   {
/* 1248 */     int lastId = getLastItemId();
/* 1249 */     int nextId = idFromRedo == -1 ? lastId + 1 : idFromRedo;
/*      */     
/* 1251 */     if (nextId > lastId) {
/* 1252 */       currentChange().itemId = nextId;
/*      */     }
/* 1254 */     return nextId;
/*      */   }
/*      */   
/*      */   MailItem.TargetConstraint getOperationTargetConstraint() {
/* 1258 */     return currentChange().tcon;
/*      */   }
/*      */   
/*      */   void setOperationTargetConstraint(MailItem.TargetConstraint tcon) {
/* 1262 */     currentChange().tcon = tcon;
/*      */   }
/*      */   
/*      */   public OperationContext getOperationContext() {
/* 1266 */     return currentChange().active ? currentChange().octxt : null;
/*      */   }
/*      */   
/*      */   RedoableOp getRedoPlayer() {
/* 1270 */     return currentChange().getRedoPlayer();
/*      */   }
/*      */   
/*      */   RedoableOp getRedoRecorder() {
/* 1274 */     return currentChange().recorder;
/*      */   }
/*      */   
/*      */   PendingModifications getPendingModifications() {
/* 1278 */     return currentChange().dirty;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   Account getAuthenticatedAccount()
/*      */   {
/* 1287 */     Account authuser = null;
/* 1288 */     if ((currentChange().active) && (currentChange().octxt != null)) {
/* 1289 */       authuser = currentChange().octxt.getAuthenticatedUser();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 1294 */     if ((authuser != null) && (authuser.getId().equals(getAccountId()))) {
/* 1295 */       authuser = null;
/*      */     }
/* 1297 */     return authuser;
/*      */   }
/*      */   
/*      */   Account getLockAccount() throws ServiceException {
/* 1301 */     Account authenticatedAccount = getAuthenticatedAccount();
/* 1302 */     if (authenticatedAccount == null) {
/* 1303 */       authenticatedAccount = getAccount();
/*      */     }
/* 1305 */     return authenticatedAccount;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean isUsingAdminPrivileges()
/*      */   {
/* 1315 */     return (currentChange().active) && (currentChange().octxt != null) && (currentChange().octxt.isUsingAdminPrivileges());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   boolean hasFullAccess()
/*      */     throws ServiceException
/*      */   {
/* 1328 */     Account authuser = getAuthenticatedAccount();
/*      */     
/* 1330 */     if ((authuser == null) || (getAccountId().equals(authuser.getId()))) {
/* 1331 */       return true;
/*      */     }
/* 1333 */     if ((currentChange().active) && (currentChange().octxt != null)) {
/* 1334 */       return AccessManager.getInstance().canAccessAccount(authuser, getAccount(), isUsingAdminPrivileges());
/*      */     }
/* 1336 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean hasFullAccess(OperationContext octxt)
/*      */     throws ServiceException
/*      */   {
/* 1345 */     Account authuser = octxt != null ? octxt.getAuthenticatedUser() : null;
/*      */     
/* 1347 */     if ((authuser == null) || (getAccountId().equals(authuser.getId()))) {
/* 1348 */       return true;
/*      */     }
/* 1350 */     return AccessManager.getInstance().canAccessAccount(authuser, getAccount(), octxt.isUsingAdminPrivileges());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public boolean hasFullAdminAccess(OperationContext octxt)
/*      */     throws ServiceException
/*      */   {
/* 1358 */     return (octxt == null) || ((octxt.isUsingAdminPrivileges()) && (hasFullAccess(octxt)));
/*      */   }
/*      */   
/*      */   public long getSize()
/*      */   {
/* 1363 */     return currentChange().size == -1L ? this.mData.size : currentChange().size;
/*      */   }
/*      */   
/*      */   void updateSize(long delta) throws ServiceException
/*      */   {
/* 1368 */     updateSize(delta, true);
/*      */   }
/*      */   
/*      */   void updateSize(long delta, boolean checkQuota) throws ServiceException {
/* 1372 */     if (delta == 0L) {
/* 1373 */       return;
/*      */     }
/*      */     
/*      */ 
/* 1377 */     long size = Math.max(0L, (currentChange().size == -1L ? this.mData.size : currentChange().size) + delta);
/*      */     
/* 1379 */     if ((delta > 0L) && (checkQuota)) {
/* 1380 */       checkSizeChange(size);
/*      */     }
/*      */     
/* 1383 */     currentChange().dirty.recordModified(this, 16);
/* 1384 */     currentChange().size = size;
/*      */   }
/*      */   
/*      */   void checkSizeChange(long newSize) throws ServiceException {
/* 1388 */     Account acct = getAccount();
/* 1389 */     long acctQuota = AccountUtil.getEffectiveQuota(acct);
/* 1390 */     if ((acctQuota != 0L) && (newSize > acctQuota)) {
/* 1391 */       throw MailServiceException.QUOTA_EXCEEDED(acctQuota);
/*      */     }
/* 1393 */     Domain domain = Provisioning.getInstance().getDomain(acct);
/* 1394 */     if ((domain != null) && (AccountUtil.isOverAggregateQuota(domain)) && (!AccountUtil.isReceiveAllowedOverAggregateQuota(domain)))
/*      */     {
/* 1396 */       throw MailServiceException.DOMAIN_QUOTA_EXCEEDED(domain.getDomainAggregateQuota());
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public long getLastSoapAccessTime()
/*      */   {
/* 1406 */     this.lock.lock(false);
/*      */     try {
/* 1408 */       long lastAccess = (currentChange().accessed == -1 ? this.mData.lastWriteDate : currentChange().accessed) * 1000L;
/*      */       
/* 1410 */       for (Session s : this.mListeners) {
/* 1411 */         if ((s instanceof SoapSession)) {
/* 1412 */           lastAccess = Math.max(lastAccess, ((SoapSession)s).getLastWriteAccessTime());
/*      */         }
/*      */       }
/* 1415 */       return lastAccess;
/*      */     } finally {
/* 1417 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public void recordLastSoapAccessTime(long time)
/*      */     throws ServiceException
/*      */   {
/* 1427 */     boolean success = false;
/*      */     try {
/* 1429 */       beginTransaction("recordLastSoapAccessTime", null);
/* 1430 */       if (time > this.mData.lastWriteDate) {
/* 1431 */         currentChange().accessed = ((int)(time / 1000L));
/* 1432 */         DbMailbox.recordLastSoapAccess(this);
/*      */       }
/* 1434 */       success = true;
/*      */     } finally {
/* 1436 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public int getRecentMessageCount()
/*      */   {
/* 1445 */     return currentChange().recent == -1 ? this.mData.recentMessages : currentChange().recent;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public void resetRecentMessageCount(OperationContext octxt)
/*      */     throws ServiceException
/*      */   {
/* 1453 */     boolean success = false;
/*      */     try {
/* 1455 */       beginTransaction("resetRecentMessageCount", octxt);
/* 1456 */       if (getRecentMessageCount() != 0) {
/* 1457 */         currentChange().recent = 0;
/*      */       }
/* 1459 */       success = true;
/*      */     } finally {
/* 1461 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void refreshMailbox(OperationContext octxt) throws ServiceException {
/* 1466 */     boolean success = false;
/*      */     try {
/* 1468 */       beginTransaction("refreshMailboxStats", octxt);
/*      */       
/* 1470 */       success = true;
/*      */     } finally {
/* 1472 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public int getContactCount()
/*      */   {
/* 1480 */     return currentChange().contacts == -1 ? this.mData.contacts : currentChange().contacts;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void updateContactCount(int delta)
/*      */     throws ServiceException
/*      */   {
/* 1493 */     if (delta == 0) {
/* 1494 */       return;
/*      */     }
/*      */     
/* 1497 */     currentChange().contacts = Math.max(0, (currentChange().contacts == -1 ? this.mData.contacts : currentChange().contacts) + delta);
/*      */     
/*      */ 
/* 1500 */     if (delta < 0) {
/* 1501 */       return;
/*      */     }
/* 1503 */     int quota = getAccount().getContactMaxNumEntries();
/* 1504 */     if ((quota != 0) && (currentChange().contacts > quota)) {
/* 1505 */       throw MailServiceException.TOO_MANY_CONTACTS(quota);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   void markItemCreated(MailItem item)
/*      */   {
/* 1514 */     currentChange().dirty.recordCreated(item);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   void markItemDeleted(MailItem item)
/*      */   {
/* 1521 */     MailItem itemSnapshot = null;
/*      */     try {
/* 1523 */       itemSnapshot = item.snapshotItem();
/*      */     } catch (ServiceException e) {
/* 1525 */       ZimbraLog.mailbox.warn("could not snapshot to-be-deleted item", e);
/*      */     }
/* 1527 */     if (itemSnapshot == null) {
/* 1528 */       markItemDeleted(item.getType(), item.getId());
/*      */     } else {
/* 1530 */       currentChange().dirty.recordDeleted(itemSnapshot);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   void markItemDeleted(MailItem.Type type, int itemId)
/*      */   {
/* 1539 */     currentChange().dirty.recordDeleted(this.mData.accountId, itemId, type);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   void markItemDeleted(TypedIdList idlist)
/*      */   {
/* 1546 */     currentChange().dirty.recordDeleted(this.mData.accountId, idlist);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void markItemModified(MailItem item, int reason)
/*      */     throws ServiceException
/*      */   {
/* 1557 */     if (item.inDumpster()) {
/* 1558 */       throw MailServiceException.IMMUTABLE_OBJECT(item.getId());
/*      */     }
/* 1560 */     currentChange().dirty.recordModified(item, reason);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean isItemModified(MailItem item, int how)
/*      */   {
/* 1571 */     PendingModifications dirty = currentChange().dirty;
/* 1572 */     if (!dirty.hasNotifications()) {
/* 1573 */       return false;
/*      */     }
/* 1575 */     PendingModifications.ModificationKey mkey = new PendingModifications.ModificationKey(item);
/* 1576 */     if ((dirty.created != null) && (dirty.created.containsKey(mkey))) {
/* 1577 */       return true;
/*      */     }
/* 1579 */     PendingModifications.Change chg = dirty.modified == null ? null : (PendingModifications.Change)dirty.modified.get(mkey);
/* 1580 */     return (chg != null) && ((chg.why & how) != 0);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void markOtherItemDirty(Object obj)
/*      */   {
/* 1596 */     if ((obj instanceof MailItem.PendingDelete)) {
/* 1597 */       currentChange().addPendingDelete((MailItem.PendingDelete)obj);
/*      */     } else {
/* 1599 */       currentChange().otherDirtyStuff.add(obj);
/*      */     }
/*      */   }
/*      */   
/*      */   public DbPool.DbConnection getOperationConnection() throws ServiceException {
/* 1604 */     if (!currentChange().isActive()) {
/* 1605 */       throw ServiceException.FAILURE("cannot fetch Connection outside transaction", new Exception());
/*      */     }
/* 1607 */     return currentChange().getConnection();
/*      */   }
/*      */   
/*      */   private void setOperationConnection(DbPool.DbConnection conn) throws ServiceException {
/* 1611 */     if (!currentChange().isActive())
/* 1612 */       throw ServiceException.FAILURE("cannot set Connection outside transaction", new Exception());
/* 1613 */     if (conn == null)
/* 1614 */       return;
/* 1615 */     if (currentChange().conn != null) {
/* 1616 */       throw ServiceException.FAILURE("cannot set Connection for in-progress transaction", new Exception());
/*      */     }
/* 1618 */     currentChange().conn = conn;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   MailboxMaintenance beginMaintenance()
/*      */     throws ServiceException
/*      */   {
/* 1630 */     this.lock.lock();
/*      */     try { MailboxMaintenance localMailboxMaintenance;
/* 1632 */       if (this.maintenance != null) {
/* 1633 */         this.maintenance.startInnerMaintenance();
/* 1634 */         ZimbraLog.mailbox.info("already in maintenance, nesting access for mailboxId %d", new Object[] { Integer.valueOf(getId()) });
/* 1635 */         return this.maintenance;
/*      */       }
/* 1637 */       ZimbraLog.mailbox.info("Putting mailbox %d under maintenance.", new Object[] { Integer.valueOf(getId()) });
/*      */       
/* 1639 */       purgeListeners();
/* 1640 */       this.index.evict();
/*      */       
/* 1642 */       this.maintenance = new MailboxMaintenance(this.mData.accountId, this.mId, this);
/* 1643 */       return this.maintenance;
/*      */     } finally {
/* 1645 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   synchronized boolean endMaintenance(boolean success)
/*      */     throws ServiceException
/*      */   {
/* 1657 */     if (this.maintenance == null) {
/* 1658 */       throw ServiceException.FAILURE("mainbox not in maintenance mode", null);
/*      */     }
/*      */     
/* 1661 */     if (success) {
/* 1662 */       ZimbraLog.mailbox.info("Ending maintenance on mailbox %d.", new Object[] { Integer.valueOf(getId()) });
/* 1663 */       if (this.maintenance.endInnerMaintenance()) {
/* 1664 */         ZimbraLog.mailbox.info("decreasing depth for mailboxId %d", new Object[] { Integer.valueOf(getId()) });
/* 1665 */         return false;
/*      */       }
/* 1667 */       this.maintenance = null;
/* 1668 */       return true;
/*      */     }
/*      */     
/* 1671 */     ZimbraLog.mailbox.info("Ending maintenance and marking mailbox %d as unavailable.", new Object[] { Integer.valueOf(getId()) });
/* 1672 */     this.maintenance.markUnavailable();
/* 1673 */     return true;
/*      */   }
/*      */   
/*      */   boolean isTransactionActive()
/*      */   {
/* 1678 */     return currentChange().depth > 0;
/*      */   }
/*      */   
/*      */   protected void beginTransaction(String caller, OperationContext octxt) throws ServiceException {
/* 1682 */     beginTransaction(caller, System.currentTimeMillis(), octxt, null, null, true);
/*      */   }
/*      */   
/*      */   protected void beginReadTransaction(String caller, OperationContext octxt) throws ServiceException {
/* 1686 */     beginTransaction(caller, System.currentTimeMillis(), octxt, null, null, false);
/*      */   }
/*      */   
/*      */   protected void beginTransaction(String caller, OperationContext octxt, RedoableOp recorder) throws ServiceException {
/* 1690 */     long timestamp = octxt == null ? System.currentTimeMillis() : octxt.getTimestamp();
/* 1691 */     beginTransaction(caller, timestamp, octxt, recorder, null, true);
/*      */   }
/*      */   
/*      */   void beginTransaction(String caller, OperationContext octxt, RedoableOp recorder, DbPool.DbConnection conn) throws ServiceException
/*      */   {
/* 1696 */     beginTransaction(caller, octxt, recorder, conn, true);
/*      */   }
/*      */   
/*      */   void beginTransaction(String caller, OperationContext octxt, RedoableOp recorder, DbPool.DbConnection conn, boolean write) throws ServiceException
/*      */   {
/* 1701 */     long timestamp = octxt == null ? System.currentTimeMillis() : octxt.getTimestamp();
/* 1702 */     beginTransaction(caller, timestamp, octxt, recorder, conn, write);
/*      */   }
/*      */   
/*      */   private void beginTransaction(String caller, long time, OperationContext octxt, RedoableOp recorder, DbPool.DbConnection conn, boolean write) throws ServiceException
/*      */   {
/* 1707 */     write = (write) || (requiresWriteLock());
/* 1708 */     assert ((recorder == null) || (write));
/* 1709 */     assert (!Thread.holdsLock(this)) : "use MailboxLock";
/* 1710 */     this.lock.lock(write);
/* 1711 */     if ((!write) && (requiresWriteLock()))
/*      */     {
/*      */ 
/* 1714 */       assert (this.lock.isWriteLockedByCurrentThread());
/* 1715 */       write = true;
/*      */     }
/*      */     
/* 1718 */     currentChange().startChange(caller, octxt, recorder, write);
/*      */     
/*      */ 
/* 1721 */     if (conn != null) {
/* 1722 */       setOperationConnection(conn);
/*      */     }
/* 1724 */     if (Zimbra.isAlwaysOn())
/*      */     {
/* 1726 */       MailboxData newData = DbMailbox.getMailboxStats(getOperationConnection(), getId());
/* 1727 */       if (newData != null) {
/* 1728 */         this.mData = newData;
/*      */       }
/*      */     }
/* 1731 */     boolean needRedo = needRedo(octxt, recorder);
/*      */     
/*      */ 
/* 1734 */     currentChange().setTimestamp(time);
/* 1735 */     if ((recorder != null) && (needRedo)) {
/* 1736 */       recorder.start(time);
/*      */     }
/*      */     
/*      */ 
/* 1740 */     if ((recorder != null) && (needRedo) && (octxt != null) && (octxt.change > 0)) {
/* 1741 */       recorder.setChangeConstraint(octxt.changetype, octxt.change);
/*      */     }
/*      */     
/*      */ 
/* 1745 */     if ((octxt != null) && (octxt.getChangeId() > 0)) {
/* 1746 */       setOperationChangeID(octxt.getChangeId());
/*      */     }
/* 1748 */     if ((recorder != null) && (needRedo)) {
/* 1749 */       recorder.setChangeId(getOperationChangeID());
/*      */     }
/*      */     
/*      */ 
/* 1753 */     ItemCache cache = (ItemCache)this.mItemCache.get();
/* 1754 */     if (cache == null) {
/* 1755 */       cache = new ItemCache(this);
/* 1756 */       this.mItemCache = new SoftReference(cache);
/* 1757 */       ZimbraLog.cache.debug("created a new MailItem cache for mailbox " + getId());
/*      */     }
/* 1759 */     currentChange().itemCache = cache;
/*      */     
/*      */ 
/* 1762 */     if ((this.maintenance != null) && (!this.maintenance.canAccess())) {
/* 1763 */       throw MailServiceException.MAINTENANCE(this.mId);
/*      */     }
/*      */     
/* 1766 */     if ((recorder != null) && (needRedo) && (currentChange().depth > 1)) {
/* 1767 */       throw ServiceException.FAILURE("cannot start a logged transaction from within another transaction (current recorder=" + currentChange().recorder + ")", null);
/*      */     }
/*      */     
/*      */ 
/* 1771 */     loadFoldersAndTags();
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public Metadata getConfig(OperationContext octxt, String section)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_2
/*      */     //   1: invokestatic 312	com/google/common/base/Strings:isNullOrEmpty	(Ljava/lang/String;)Z
/*      */     //   4: ifeq +5 -> 9
/*      */     //   7: aconst_null
/*      */     //   8: areturn
/*      */     //   9: iconst_1
/*      */     //   10: istore_3
/*      */     //   11: aload_0
/*      */     //   12: ldc_w 313
/*      */     //   15: aload_1
/*      */     //   16: aconst_null
/*      */     //   17: invokevirtual 314	com/zimbra/cs/mailbox/Mailbox:beginTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;Lcom/zimbra/cs/redolog/op/RedoableOp;)V
/*      */     //   20: aload_0
/*      */     //   21: invokevirtual 315	com/zimbra/cs/mailbox/Mailbox:hasFullAccess	()Z
/*      */     //   24: ifne +14 -> 38
/*      */     //   27: aconst_null
/*      */     //   28: astore 4
/*      */     //   30: aload_0
/*      */     //   31: iload_3
/*      */     //   32: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   35: aload 4
/*      */     //   37: areturn
/*      */     //   38: aload_0
/*      */     //   39: getfield 31	com/zimbra/cs/mailbox/Mailbox:mData	Lcom/zimbra/cs/mailbox/Mailbox$MailboxData;
/*      */     //   42: getfield 316	com/zimbra/cs/mailbox/Mailbox$MailboxData:configKeys	Ljava/util/Set;
/*      */     //   45: ifnull +19 -> 64
/*      */     //   48: aload_0
/*      */     //   49: getfield 31	com/zimbra/cs/mailbox/Mailbox:mData	Lcom/zimbra/cs/mailbox/Mailbox$MailboxData;
/*      */     //   52: getfield 316	com/zimbra/cs/mailbox/Mailbox$MailboxData:configKeys	Ljava/util/Set;
/*      */     //   55: aload_2
/*      */     //   56: invokeinterface 317 2 0
/*      */     //   61: ifne +14 -> 75
/*      */     //   64: aconst_null
/*      */     //   65: astore 4
/*      */     //   67: aload_0
/*      */     //   68: iload_3
/*      */     //   69: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   72: aload 4
/*      */     //   74: areturn
/*      */     //   75: aload_0
/*      */     //   76: aload_2
/*      */     //   77: invokestatic 318	com/zimbra/cs/db/DbMailbox:getConfig	(Lcom/zimbra/cs/mailbox/Mailbox;Ljava/lang/String;)Ljava/lang/String;
/*      */     //   80: astore 4
/*      */     //   82: aload 4
/*      */     //   84: ifnonnull +14 -> 98
/*      */     //   87: aconst_null
/*      */     //   88: astore 5
/*      */     //   90: aload_0
/*      */     //   91: iload_3
/*      */     //   92: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   95: aload 5
/*      */     //   97: areturn
/*      */     //   98: new 319	com/zimbra/cs/mailbox/Metadata
/*      */     //   101: dup
/*      */     //   102: aload 4
/*      */     //   104: invokespecial 320	com/zimbra/cs/mailbox/Metadata:<init>	(Ljava/lang/String;)V
/*      */     //   107: astore 5
/*      */     //   109: aload_0
/*      */     //   110: iload_3
/*      */     //   111: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   114: aload 5
/*      */     //   116: areturn
/*      */     //   117: astore 5
/*      */     //   119: iconst_0
/*      */     //   120: istore_3
/*      */     //   121: getstatic 67	com/zimbra/common/util/ZimbraLog:mailbox	Lcom/zimbra/common/util/Log;
/*      */     //   124: new 56	java/lang/StringBuilder
/*      */     //   127: dup
/*      */     //   128: invokespecial 57	java/lang/StringBuilder:<init>	()V
/*      */     //   131: ldc_w 321
/*      */     //   134: invokevirtual 59	java/lang/StringBuilder:append	(Ljava/lang/String;)Ljava/lang/StringBuilder;
/*      */     //   137: aload_2
/*      */     //   138: invokevirtual 59	java/lang/StringBuilder:append	(Ljava/lang/String;)Ljava/lang/StringBuilder;
/*      */     //   141: invokevirtual 62	java/lang/StringBuilder:toString	()Ljava/lang/String;
/*      */     //   144: invokevirtual 322	com/zimbra/common/util/Log:warn	(Ljava/lang/Object;)V
/*      */     //   147: aconst_null
/*      */     //   148: astore 6
/*      */     //   150: aload_0
/*      */     //   151: iload_3
/*      */     //   152: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   155: aload 6
/*      */     //   157: areturn
/*      */     //   158: astore 7
/*      */     //   160: aload_0
/*      */     //   161: iload_3
/*      */     //   162: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   165: aload 7
/*      */     //   167: athrow
/*      */     // Line number table:
/*      */     //   Java source line #1788	-> byte code offset #0
/*      */     //   Java source line #1789	-> byte code offset #7
/*      */     //   Java source line #1793	-> byte code offset #9
/*      */     //   Java source line #1795	-> byte code offset #11
/*      */     //   Java source line #1797	-> byte code offset #20
/*      */     //   Java source line #1798	-> byte code offset #27
/*      */     //   Java source line #1815	-> byte code offset #30
/*      */     //   Java source line #1800	-> byte code offset #38
/*      */     //   Java source line #1801	-> byte code offset #64
/*      */     //   Java source line #1815	-> byte code offset #67
/*      */     //   Java source line #1803	-> byte code offset #75
/*      */     //   Java source line #1804	-> byte code offset #82
/*      */     //   Java source line #1805	-> byte code offset #87
/*      */     //   Java source line #1815	-> byte code offset #90
/*      */     //   Java source line #1808	-> byte code offset #98
/*      */     //   Java source line #1815	-> byte code offset #109
/*      */     //   Java source line #1809	-> byte code offset #117
/*      */     //   Java source line #1810	-> byte code offset #119
/*      */     //   Java source line #1811	-> byte code offset #121
/*      */     //   Java source line #1812	-> byte code offset #147
/*      */     //   Java source line #1815	-> byte code offset #150
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	168	0	this	Mailbox
/*      */     //   0	168	1	octxt	OperationContext
/*      */     //   0	168	2	section	String
/*      */     //   10	152	3	success	boolean
/*      */     //   28	45	4	localMetadata1	Metadata
/*      */     //   80	23	4	config	String
/*      */     //   88	27	5	localMetadata2	Metadata
/*      */     //   117	3	5	e	ServiceException
/*      */     //   148	8	6	localMetadata3	Metadata
/*      */     //   158	8	7	localObject	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   98	109	117	com/zimbra/common/service/ServiceException
/*      */     //   11	30	158	finally
/*      */     //   38	67	158	finally
/*      */     //   75	90	158	finally
/*      */     //   98	109	158	finally
/*      */     //   117	150	158	finally
/*      */     //   158	160	158	finally
/*      */   }
/*      */   
/*      */   public void setConfig(OperationContext octxt, String section, Metadata config)
/*      */     throws ServiceException
/*      */   {
/* 1833 */     Preconditions.checkNotNull(section);
/*      */     
/* 1835 */     SetConfig redoPlayer = new SetConfig(this.mId, section, config);
/* 1836 */     boolean success = false;
/*      */     try {
/* 1838 */       beginTransaction("setConfig", octxt, redoPlayer);
/*      */       
/*      */ 
/* 1841 */       if (!hasFullAccess()) {
/* 1842 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */       }
/* 1844 */       currentChange().dirty.recordModified(this, 8);
/* 1845 */       currentChange().config = new Pair(section, config);
/* 1846 */       DbMailbox.updateConfig(this, section, config);
/* 1847 */       success = true;
/*      */     } finally {
/* 1849 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void deleteConfig(OperationContext octxt, String sectionPart)
/*      */     throws ServiceException
/*      */   {
/* 1861 */     Preconditions.checkNotNull(sectionPart);
/*      */     
/* 1863 */     DeleteConfig redoPlayer = new DeleteConfig(this.mId, sectionPart);
/* 1864 */     boolean success = false;
/*      */     try {
/* 1866 */       beginTransaction("deleteConfig", octxt, redoPlayer);
/*      */       
/*      */ 
/* 1869 */       if (!hasFullAccess()) {
/* 1870 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */       }
/* 1872 */       currentChange().dirty.recordModified(this, 8);
/* 1873 */       DbMailbox.deleteConfig(this, sectionPart);
/* 1874 */       success = true;
/*      */     } finally {
/* 1876 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private ItemCache getItemCache() throws ServiceException {
/* 1881 */     if (!currentChange().isActive()) {
/* 1882 */       throw ServiceException.FAILURE("cannot access item cache outside a transaction active=" + currentChange().active + ",depth=" + currentChange().depth, null);
/*      */     }
/*      */     
/* 1885 */     return currentChange().itemCache;
/*      */   }
/*      */   
/*      */   private void clearItemCache() {
/* 1889 */     if (currentChange().isActive()) {
/* 1890 */       currentChange().itemCache.clear();
/*      */     } else {
/* 1892 */       this.mItemCache.clear();
/*      */     }
/*      */     try {
/* 1895 */       if (Zimbra.isAlwaysOn()) {
/* 1896 */         DbMailbox.incrementItemcacheCheckpoint(this);
/*      */       }
/*      */     } catch (ServiceException e) {
/* 1899 */       ZimbraLog.mailbox.error("error while clearing item cache", e);
/*      */     }
/*      */   }
/*      */   
/*      */   void cache(MailItem item) throws ServiceException {
/* 1904 */     if ((item == null) || (item.isTagged(Flag.FlagInfo.UNCACHED))) {
/* 1905 */       return;
/*      */     }
/*      */     
/* 1908 */     if ((item instanceof Tag)) {
/* 1909 */       if (this.mTagCache != null) {
/* 1910 */         this.mTagCache.put(Integer.valueOf(item.getId()), (Tag)item);
/* 1911 */         this.mTagCache.put(item.getName().toLowerCase(), (Tag)item);
/*      */       }
/* 1913 */     } else if ((item instanceof Folder)) {
/* 1914 */       if (this.mFolderCache != null) {
/* 1915 */         this.mFolderCache.put((Folder)item);
/*      */       }
/*      */     } else {
/* 1918 */       getItemCache().put(item);
/*      */     }
/*      */     
/* 1921 */     ZimbraLog.cache.debug("cached %s %d in mailbox %d", new Object[] { item.getType(), Integer.valueOf(item.getId()), Integer.valueOf(getId()) });
/*      */   }
/*      */   
/*      */   protected void uncache(MailItem item) throws ServiceException {
/* 1925 */     if (item == null) {
/* 1926 */       return;
/*      */     }
/*      */     
/* 1929 */     if ((item instanceof Tag)) {
/* 1930 */       if (this.mTagCache == null) {
/* 1931 */         return;
/*      */       }
/* 1933 */       this.mTagCache.remove(Integer.valueOf(item.getId()));
/* 1934 */       this.mTagCache.remove(item.getName().toLowerCase());
/* 1935 */     } else if ((item instanceof Folder)) {
/* 1936 */       if (this.mFolderCache == null) {
/* 1937 */         return;
/*      */       }
/* 1939 */       this.mFolderCache.remove((Folder)item);
/*      */     } else {
/* 1941 */       getItemCache().remove(item);
/* 1942 */       MessageCache.purge(item);
/*      */     }
/*      */     
/* 1945 */     ZimbraLog.cache.debug("uncached %s %d in mailbox %d", new Object[] { item.getType(), Integer.valueOf(item.getId()), Integer.valueOf(getId()) });
/*      */     
/* 1947 */     uncacheChildren(item);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void uncacheItem(Integer itemId)
/*      */     throws ServiceException
/*      */   {
/* 1958 */     MailItem item = getItemCache().remove(itemId.intValue());
/* 1959 */     if (ZimbraLog.cache.isDebugEnabled()) {
/* 1960 */       ZimbraLog.cache.debug("uncached item " + itemId + " in mailbox " + getId());
/*      */     }
/* 1962 */     if (item != null) {
/* 1963 */       MessageCache.purge(item);
/*      */     } else {
/* 1965 */       MessageCache.purge(this, itemId.intValue());
/*      */     }
/*      */   }
/*      */   
/*      */   void uncacheChildren(MailItem parent)
/*      */     throws ServiceException
/*      */   {
/* 1972 */     if ((parent == null) || (!parent.canHaveChildren())) {
/*      */       return;
/*      */     }
/*      */     
/*      */     Collection<? extends MailItem> cached;
/* 1977 */     if (!(parent instanceof Folder)) {
/* 1978 */       cached = getItemCache().values(); } else { Collection<? extends MailItem> cached;
/* 1979 */       if (this.mFolderCache != null)
/* 1980 */         cached = this.mFolderCache.values(); else {
/*      */         return;
/*      */       }
/*      */     }
/*      */     Collection<? extends MailItem> cached;
/* 1985 */     int parentId = parent.getId();
/* 1986 */     List<MailItem> children = new ArrayList();
/* 1987 */     for (MailItem item : cached) {
/* 1988 */       if (item.getParentId() == parentId) {
/* 1989 */         children.add(item);
/*      */       }
/*      */     }
/*      */     
/* 1993 */     if (!children.isEmpty()) {
/* 1994 */       for (MailItem child : children) {
/* 1995 */         uncache(child);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   private void clearFolderCache() {
/* 2001 */     this.mFolderCache = null;
/* 2002 */     this.requiresWriteLock = true;
/*      */     try
/*      */     {
/* 2005 */       FoldersTagsCache.getInstance().purgeMailbox(this);
/*      */     } catch (ServiceException e) {
/* 2007 */       ZimbraLog.mailbox.warn("error deleting folders/tags cache from memcached.");
/*      */     }
/*      */   }
/*      */   
/*      */   private void clearTagCache() {
/* 2012 */     this.mTagCache = null;
/* 2013 */     this.requiresWriteLock = true;
/*      */     try
/*      */     {
/* 2016 */       FoldersTagsCache.getInstance().purgeMailbox(this);
/*      */     } catch (ServiceException e) {
/* 2018 */       ZimbraLog.mailbox.warn("error deleting folders/tags cache from memcached.");
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void purge(MailItem.Type type)
/*      */   {
/* 2029 */     this.lock.lock();
/*      */     try {
/* 2031 */       switch (type) {
/*      */       case FOLDER: 
/*      */       case MOUNTPOINT: 
/*      */       case SEARCHFOLDER: 
/* 2035 */         clearFolderCache();
/* 2036 */         break;
/*      */       case FLAG: 
/*      */       case TAG: 
/* 2039 */         clearTagCache();
/* 2040 */         break;
/*      */       default: 
/* 2042 */         clearItemCache();
/* 2043 */         break;
/*      */       case UNKNOWN: 
/* 2045 */         clearFolderCache();
/* 2046 */         clearTagCache();
/* 2047 */         clearItemCache();
/*      */       }
/*      */     }
/*      */     finally {
/* 2051 */       this.lock.release();
/*      */     }
/*      */     
/* 2054 */     ZimbraLog.cache.debug("purged type=%s", new Object[] { type });
/*      */   }
/*      */   
/* 2057 */   public static final Set<Integer> REIFIED_FLAGS = ImmutableSet.of(Integer.valueOf(Flag.ID_FROM_ME), Integer.valueOf(Flag.ID_ATTACHED), Integer.valueOf(Flag.ID_REPLIED), Integer.valueOf(Flag.ID_FORWARDED), Integer.valueOf(Flag.ID_COPIED), Integer.valueOf(Flag.ID_FLAGGED), new Integer[] { Integer.valueOf(Flag.ID_DRAFT), Integer.valueOf(Flag.ID_DELETED), Integer.valueOf(Flag.ID_NOTIFIED), Integer.valueOf(Flag.ID_UNREAD), Integer.valueOf(Flag.ID_HIGH_PRIORITY), Integer.valueOf(Flag.ID_LOW_PRIORITY), Integer.valueOf(Flag.ID_VERSIONED), Integer.valueOf(Flag.ID_POPPED), Integer.valueOf(Flag.ID_NOTE), Integer.valueOf(Flag.ID_PRIORITY), Integer.valueOf(Flag.ID_INVITE), Integer.valueOf(Flag.ID_POST), Integer.valueOf(Flag.ID_MUTED) });
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected void initialize()
/*      */     throws ServiceException
/*      */   {
/* 2084 */     this.lock.lock();
/*      */     try {
/* 2086 */       createDefaultFolders();
/* 2087 */       createDefaultFlags();
/*      */       
/* 2089 */       currentChange().itemId = getInitialItemId();
/* 2090 */       DbMailbox.updateMailboxStats(this);
/*      */     } finally {
/* 2092 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   protected void createDefaultFolders()
/*      */     throws ServiceException
/*      */   {
/* 2099 */     this.lock.lock();
/*      */     try {
/* 2101 */       byte hidden = 3;
/* 2102 */       Folder root = Folder.create(11, UUIDUtil.generateUUID(), this, null, "ROOT", hidden, MailItem.Type.UNKNOWN, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2104 */       Folder.create(8, UUIDUtil.generateUUID(), this, root, "Tags", hidden, MailItem.Type.TAG, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2106 */       Folder.create(9, UUIDUtil.generateUUID(), this, root, "Conversations", hidden, MailItem.Type.CONVERSATION, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2108 */       Folder.create(17, UUIDUtil.generateUUID(), this, root, "Comments", hidden, MailItem.Type.COMMENT, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/*      */ 
/* 2111 */       byte system = 1;
/* 2112 */       Folder userRoot = Folder.create(1, UUIDUtil.generateUUID(), this, root, "USER_ROOT", system, MailItem.Type.UNKNOWN, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2114 */       Folder.create(2, UUIDUtil.generateUUID(), this, userRoot, "Inbox", system, MailItem.Type.MESSAGE, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2116 */       Folder.create(3, UUIDUtil.generateUUID(), this, userRoot, "Trash", system, MailItem.Type.UNKNOWN, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2118 */       Folder.create(4, UUIDUtil.generateUUID(), this, userRoot, "Junk", system, MailItem.Type.MESSAGE, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2120 */       Folder.create(5, UUIDUtil.generateUUID(), this, userRoot, "Sent", system, MailItem.Type.MESSAGE, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2122 */       Folder.create(6, UUIDUtil.generateUUID(), this, userRoot, "Drafts", system, MailItem.Type.MESSAGE, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2124 */       Folder.create(7, UUIDUtil.generateUUID(), this, userRoot, "Contacts", system, MailItem.Type.CONTACT, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2126 */       Folder.create(10, UUIDUtil.generateUUID(), this, userRoot, "Calendar", system, MailItem.Type.APPOINTMENT, Flag.BITMASK_CHECKED, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/*      */ 
/* 2129 */       Folder.create(15, UUIDUtil.generateUUID(), this, userRoot, "Tasks", system, MailItem.Type.TASK, Flag.BITMASK_CHECKED, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2131 */       Folder.create(13, UUIDUtil.generateUUID(), this, userRoot, "Emailed Contacts", system, MailItem.Type.CONTACT, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2133 */       Folder.create(14, UUIDUtil.generateUUID(), this, userRoot, "Chats", system, MailItem.Type.MESSAGE, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */       
/* 2135 */       Folder.create(16, UUIDUtil.generateUUID(), this, userRoot, "Briefcase", system, MailItem.Type.DOCUMENT, 0, MailItem.DEFAULT_COLOR_RGB, null, null, null);
/*      */     }
/*      */     finally {
/* 2138 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   void createDefaultFlags() throws ServiceException {
/* 2143 */     this.lock.lock();
/*      */     try
/*      */     {
/* 2146 */       for (i$ = REIFIED_FLAGS.iterator(); i$.hasNext();) { int tagId = ((Integer)i$.next()).intValue();
/* 2147 */         DbTag.createTag(this, Flag.of(this, tagId).mData, null, false);
/*      */       }
/*      */     } finally { Iterator i$;
/* 2150 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   int getInitialItemId() {
/* 2155 */     return 256;
/*      */   }
/*      */   
/*      */   private void loadFoldersAndTags() throws ServiceException
/*      */   {
/* 2160 */     boolean initial = (this.mData.contacts < 0) || (this.mData.size < 0L);
/* 2161 */     if (((!Zimbra.isAlwaysOn()) || (this.lock.getHoldCount() > 1)) && 
/* 2162 */       (this.mFolderCache != null) && (this.mTagCache != null) && (!initial)) {
/* 2163 */       return;
/*      */     }
/*      */     
/* 2166 */     if (ZimbraLog.cache.isDebugEnabled()) {
/* 2167 */       ZimbraLog.cache.debug("loading due to initial? %s folders? %s tags? %s writeChange? %s", new Object[] { Boolean.valueOf(initial), Boolean.valueOf(this.mFolderCache == null ? 1 : false), Boolean.valueOf(this.mTagCache == null ? 1 : false), Boolean.valueOf(currentChange().writeChange) });
/*      */     }
/* 2169 */     assert (currentChange().writeChange);
/* 2170 */     assert (this.lock.isWriteLockedByCurrentThread());
/*      */     
/* 2172 */     ZimbraLog.cache.info("initializing folder and tag caches for mailbox %d", new Object[] { Integer.valueOf(getId()) });
/*      */     try {
/* 2174 */       DbMailItem.FolderTagMap folderData = new DbMailItem.FolderTagMap();
/* 2175 */       DbMailItem.FolderTagMap tagData = new DbMailItem.FolderTagMap();
/* 2176 */       MailboxData stats = null;
/*      */       
/*      */ 
/* 2179 */       boolean loadedFromMemcached = false;
/* 2180 */       if ((!initial) && (!DebugConfig.disableFoldersTagsCache)) {
/* 2181 */         FoldersTagsCache ftCache = FoldersTagsCache.getInstance();
/* 2182 */         FoldersTagsCache.FoldersTags ftData = ftCache.get(this);
/* 2183 */         if (ftData != null) {
/* 2184 */           List<Metadata> foldersMeta = ftData.getFolders();
/* 2185 */           for (Metadata meta : foldersMeta) {
/* 2186 */             MailItem.UnderlyingData ud = new MailItem.UnderlyingData();
/* 2187 */             ud.deserialize(meta);
/* 2188 */             folderData.put(ud, null);
/*      */           }
/* 2190 */           List<Metadata> tagsMeta = ftData.getTags();
/* 2191 */           for (Metadata meta : tagsMeta) {
/* 2192 */             MailItem.UnderlyingData ud = new MailItem.UnderlyingData();
/* 2193 */             ud.deserialize(meta);
/* 2194 */             tagData.put(ud, null);
/*      */           }
/* 2196 */           loadedFromMemcached = true;
/*      */         }
/*      */       }
/*      */       
/* 2200 */       if (!loadedFromMemcached) {
/* 2201 */         stats = DbMailItem.getFoldersAndTags(this, folderData, tagData, initial);
/*      */       }
/*      */       
/* 2204 */       boolean persist = stats != null;
/* 2205 */       if (stats != null) {
/* 2206 */         if (this.mData.size != stats.size) {
/* 2207 */           currentChange().dirty.recordModified(this, 16);
/* 2208 */           ZimbraLog.mailbox.debug("setting mailbox size to %d (was %d) for mailbox %d", new Object[] { Long.valueOf(stats.size), Long.valueOf(this.mData.size), Integer.valueOf(this.mId) });
/*      */           
/* 2210 */           this.mData.size = stats.size;
/*      */         }
/* 2212 */         if (this.mData.contacts != stats.contacts) {
/* 2213 */           ZimbraLog.mailbox.debug("setting contact count to %d (was %d) for mailbox %d", new Object[] { Integer.valueOf(stats.contacts), Integer.valueOf(this.mData.contacts), Integer.valueOf(this.mId) });
/*      */           
/* 2215 */           this.mData.contacts = stats.contacts;
/*      */         }
/* 2217 */         DbMailbox.updateMailboxStats(this);
/*      */       }
/*      */       
/* 2220 */       this.mFolderCache = new FolderCache();
/*      */       
/* 2222 */       for (Map.Entry<MailItem.UnderlyingData, DbMailItem.FolderTagCounts> entry : folderData.entrySet()) {
/* 2223 */         Folder folder = (Folder)MailItem.constructItem(this, (MailItem.UnderlyingData)entry.getKey());
/* 2224 */         DbMailItem.FolderTagCounts fcounts = (DbMailItem.FolderTagCounts)entry.getValue();
/* 2225 */         if (fcounts != null) {
/* 2226 */           folder.setSize(folder.getItemCount(), fcounts.deletedCount, fcounts.totalSize, fcounts.deletedUnreadCount);
/*      */         }
/*      */       }
/*      */       
/* 2230 */       for (Folder folder : this.mFolderCache.values()) {
/* 2231 */         Folder parent = this.mFolderCache.get(folder.getFolderId());
/*      */         
/* 2233 */         if (parent != null) {
/* 2234 */           parent.addChild(folder, false);
/*      */         }
/*      */         
/* 2237 */         boolean badChangeDate = folder.getChangeDate() <= 0L;
/* 2238 */         if (badChangeDate) {
/* 2239 */           markItemModified(folder, 268435456);
/* 2240 */           folder.metadataChanged();
/*      */         }
/*      */         
/* 2243 */         if ((persist) || (badChangeDate)) {
/* 2244 */           folder.saveFolderCounts(initial);
/*      */         }
/*      */       }
/*      */       
/* 2248 */       this.mTagCache = new ConcurrentHashMap(tagData.size() * 3);
/*      */       
/*      */ 
/* 2251 */       for (Map.Entry<MailItem.UnderlyingData, DbMailItem.FolderTagCounts> entry : tagData.entrySet()) {
/* 2252 */         Tag tag = new Tag(this, (MailItem.UnderlyingData)entry.getKey());
/* 2253 */         if (persist) {
/* 2254 */           tag.saveTagCounts();
/*      */         }
/*      */       }
/*      */       
/* 2258 */       if ((!loadedFromMemcached) && (!DebugConfig.disableFoldersTagsCache)) {
/* 2259 */         cacheFoldersTagsToMemcached();
/*      */       }
/* 2261 */       if (this.requiresWriteLock) {
/* 2262 */         this.requiresWriteLock = false;
/* 2263 */         ZimbraLog.mailbox.debug("consuming forceWriteMode");
/*      */       }
/*      */     }
/*      */     catch (ServiceException e) {
/* 2267 */       this.mTagCache = null;
/* 2268 */       this.mFolderCache = null;
/* 2269 */       throw e;
/*      */     }
/*      */   }
/*      */   
/*      */   void cacheFoldersTagsToMemcached() throws ServiceException {
/* 2274 */     this.lock.lock();
/*      */     try {
/* 2276 */       List<Folder> folderList = new ArrayList(this.mFolderCache.values());
/* 2277 */       List<Tag> tagList = new ArrayList();
/* 2278 */       for (Map.Entry<Object, Tag> entry : this.mTagCache.entrySet())
/*      */       {
/* 2280 */         if ((entry.getKey() instanceof String)) {
/* 2281 */           tagList.add(entry.getValue());
/*      */         }
/*      */       }
/* 2284 */       FoldersTagsCache.FoldersTags ftData = new FoldersTagsCache.FoldersTags(folderList, tagList);
/* 2285 */       FoldersTagsCache ftCache = FoldersTagsCache.getInstance();
/* 2286 */       ftCache.put(this, ftData);
/*      */     } finally {
/* 2288 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public void recalculateFolderAndTagCounts() throws ServiceException {
/* 2293 */     boolean success = false;
/*      */     try {
/* 2295 */       beginTransaction("recalculateFolderAndTagCounts", null);
/*      */       
/*      */ 
/* 2298 */       clearFolderCache();
/* 2299 */       clearTagCache();
/* 2300 */       this.mData.contacts = -1;
/* 2301 */       loadFoldersAndTags();
/*      */       
/* 2303 */       success = true;
/*      */     } finally {
/* 2305 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void deleteMailbox() throws ServiceException {
/* 2310 */     deleteMailbox(DeleteBlobs.ALWAYS);
/*      */   }
/*      */   
/*      */   public static enum DeleteBlobs {
/* 2314 */     ALWAYS,  NEVER,  UNLESS_CENTRALIZED;
/*      */     
/*      */     private DeleteBlobs() {}
/*      */   }
/*      */   
/*      */   private static class MessageCachePurgeCallback implements DbMailItem.Callback<String> {
/* 2320 */     public void call(String value) { MessageCache.purge(value); }
/*      */   }
/*      */   
/*      */   public void deleteMailbox(DeleteBlobs deleteBlobs) throws ServiceException
/*      */   {
/* 2325 */     StoreManager sm = StoreManager.getInstance();
/* 2326 */     boolean deleteStore = (deleteBlobs == DeleteBlobs.ALWAYS) || ((deleteBlobs == DeleteBlobs.UNLESS_CENTRALIZED) && (!sm.supports(StoreManager.StoreFeature.CENTRALIZED)));
/*      */     
/* 2328 */     SpoolingCache<MailboxBlob.MailboxBlobInfo> blobs = null;
/*      */     
/* 2330 */     this.lock.lock();
/*      */     
/*      */     try
/*      */     {
/* 2334 */       MailboxMaintenance maint = null;
/*      */       try {
/* 2336 */         maint = MailboxManager.getInstance().beginMaintenance(this.mData.accountId, this.mId);
/*      */ 
/*      */       }
/*      */       catch (MailServiceException e)
/*      */       {
/* 2341 */         if (!"mail.WRONG_MAILBOX".equals(e.getCode())) {
/* 2342 */           throw e;
/*      */         }
/*      */       }
/*      */       
/* 2346 */       DeleteMailbox redoRecorder = new DeleteMailbox(this.mId);
/* 2347 */       boolean needRedo = needRedo(null, redoRecorder);
/* 2348 */       boolean success = false;
/*      */       try {
/* 2350 */         beginTransaction("deleteMailbox", null, redoRecorder);
/* 2351 */         if (needRedo) {
/* 2352 */           redoRecorder.log();
/*      */         }
/*      */         
/* 2355 */         if ((deleteStore) && (!sm.supports(StoreManager.StoreFeature.BULK_DELETE))) {
/* 2356 */           blobs = DbMailItem.getAllBlobs(this);
/*      */         }
/*      */         
/*      */         try
/*      */         {
/* 2361 */           if (deleteStore) {
/* 2362 */             DbMailItem.visitAllBlobDigests(this, new MessageCachePurgeCallback(null));
/*      */           }
/*      */           
/* 2365 */           DbPool.DbConnection conn = getOperationConnection();
/* 2366 */           DbMailbox.clearMailboxContent(this);
/* 2367 */           DbMailbox.deleteMailbox(conn, this);
/* 2368 */           DbVolumeBlobs.deleteBlobRef(conn, this);
/*      */           
/*      */ 
/* 2371 */           MemcachedCacheManager.purgeMailbox(this);
/*      */           
/* 2373 */           success = true;
/*      */         }
/*      */         finally {
/* 2376 */           endTransaction(success);
/*      */         }
/*      */         
/* 2379 */         if (success)
/*      */         {
/*      */ 
/* 2382 */           MailboxManager.getInstance().markMailboxDeleted(this);
/*      */           
/*      */           try
/*      */           {
/* 2386 */             this.index.deleteIndex();
/*      */           } catch (IOException iox) {
/* 2388 */             ZimbraLog.store.warn("Unable to delete index data", iox);
/*      */           }
/*      */           
/* 2391 */           if (deleteStore) {
/*      */             try {
/* 2393 */               sm.deleteStore(this, blobs);
/*      */             } catch (IOException iox) {
/* 2395 */               ZimbraLog.store.warn("Unable to delete message data", iox);
/*      */             }
/*      */           }
/*      */         }
/*      */       } finally {
/* 2400 */         if (needRedo) {
/* 2401 */           if (success) {
/* 2402 */             redoRecorder.commit();
/*      */           } else {
/* 2404 */             redoRecorder.abort();
/*      */           }
/*      */         }
/*      */         
/* 2408 */         if (maint != null) {
/* 2409 */           if (success)
/*      */           {
/*      */ 
/* 2412 */             maint.markUnavailable();
/*      */           }
/*      */           else {
/* 2415 */             MailboxManager.getInstance().endMaintenance(maint, success, true);
/*      */           }
/*      */         }
/*      */         
/* 2419 */         if (blobs != null) {
/* 2420 */           blobs.cleanup();
/*      */         }
/*      */       }
/*      */     } finally {
/* 2424 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public void renameMailbox(String oldName, String newName) throws ServiceException {
/* 2429 */     renameMailbox(null, oldName, newName);
/*      */   }
/*      */   
/*      */   public void renameMailbox(OperationContext octxt, String oldName, String newName) throws ServiceException {
/* 2433 */     if (Strings.isNullOrEmpty(newName)) {
/* 2434 */       throw ServiceException.INVALID_REQUEST("Cannot rename mailbox to empty name", null);
/*      */     }
/* 2436 */     RenameMailbox redoRecorder = new RenameMailbox(this.mId, oldName, newName);
/* 2437 */     boolean success = false;
/*      */     try {
/* 2439 */       beginTransaction("renameMailbox", octxt, redoRecorder);
/*      */       
/* 2441 */       DbMailbox.renameMailbox(this, newName);
/* 2442 */       success = true;
/*      */     } finally {
/* 2444 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public MailboxVersion getVersion() {
/* 2449 */     this.lock.lock();
/*      */     try {
/* 2451 */       return this.mData.version;
/*      */     } finally {
/* 2453 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public void resetMailboxForRestore() throws ServiceException {
/* 2458 */     boolean success = false;
/*      */     try {
/* 2460 */       beginTransaction("resetMailboxForRestore", null);
/* 2461 */       for (Iterator i$ = REIFIED_FLAGS.iterator(); i$.hasNext();) { int tagId = ((Integer)i$.next()).intValue();
/* 2462 */         DbTag.deleteTagRow(this, tagId);
/*      */       }
/* 2464 */       DbMailbox.updateVersion(this, null);
/* 2465 */       success = true;
/*      */     } finally {
/* 2467 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   void updateVersion(MailboxVersion vers) throws ServiceException {
/* 2472 */     boolean success = false;
/*      */     try {
/* 2474 */       beginTransaction("updateVersion", null);
/*      */       
/*      */ 
/* 2477 */       if ((this.mData.configKeys != null) && (this.mData.configKeys.contains("ver"))) {
/* 2478 */         currentChange().dirty.recordModified(this, 8);
/* 2479 */         currentChange().config = new Pair("ver", null);
/* 2480 */         DbMailbox.updateConfig(this, "ver", null);
/*      */       }
/*      */       
/*      */ 
/* 2484 */       MailboxVersion version = new MailboxVersion(vers);
/* 2485 */       DbMailbox.updateVersion(this, version);
/* 2486 */       this.mData.version = version;
/* 2487 */       success = true;
/*      */     } finally {
/* 2489 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void reanalyze(int id, MailItem.Type type, Object data, long size)
/*      */     throws ServiceException
/*      */   {
/* 2502 */     boolean success = false;
/*      */     try {
/* 2504 */       beginTransaction("reanalyze", null);
/*      */       MailItem item;
/*      */       try {
/* 2507 */         item = getItemById(id, type, false);
/*      */       } catch (MailServiceException.NoSuchItemException e) {
/* 2509 */         item = getItemById(id, type, true);
/*      */       }
/* 2511 */       item.reanalyze(data, size);
/* 2512 */       success = true;
/*      */     } finally {
/* 2514 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public short getEffectivePermissions(OperationContext octxt, int itemId, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 2553 */     boolean success = false;
/*      */     try {
/* 2555 */       beginReadTransaction("getEffectivePermissions", octxt);
/*      */       
/*      */ 
/*      */ 
/* 2559 */       MailItem item = getItemById(itemId, type);
/*      */       
/*      */ 
/* 2562 */       short rights = item.checkRights((short)-1, getAuthenticatedAccount(), isUsingAdminPrivileges());
/* 2563 */       success = true;
/* 2564 */       return rights;
/*      */     } finally {
/* 2566 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public short getEffectivePermissions(Account authedAcct, boolean asAdmin, int itemId, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 2578 */     boolean success = false;
/*      */     try {
/* 2580 */       beginReadTransaction("getEffectivePermissions", new OperationContext(authedAcct, asAdmin));
/*      */       
/*      */ 
/*      */ 
/* 2584 */       MailItem item = getItemById(itemId, type);
/*      */       
/*      */ 
/* 2587 */       short rights = item.checkRights((short)-1, authedAcct, asAdmin);
/* 2588 */       success = true;
/* 2589 */       return rights;
/*      */     } finally {
/* 2591 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static boolean isCachedType(MailItem.Type type)
/*      */   {
/* 2604 */     switch (type) {
/*      */     case FOLDER: 
/*      */     case MOUNTPOINT: 
/*      */     case SEARCHFOLDER: 
/*      */     case FLAG: 
/*      */     case TAG: 
/* 2610 */       return true;
/*      */     }
/* 2612 */     return false;
/*      */   }
/*      */   
/*      */   protected <T extends MailItem> T checkAccess(T item) throws ServiceException
/*      */   {
/* 2617 */     if ((item == null) || (item.canAccess((short)1))) {
/* 2618 */       return item;
/*      */     }
/* 2620 */     throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private <T extends MailItem> T snapshotItem(T item)
/*      */     throws ServiceException
/*      */   {
/* 2636 */     if ((item == null) || (item.isTagged(Flag.FlagInfo.UNCACHED)) || (currentChange().depth > 1)) {
/* 2637 */       return item;
/*      */     }
/* 2639 */     if ((item instanceof Folder)) {
/* 2640 */       return this.mFolderCache == null ? item : snapshotFolders().get(item.getId());
/*      */     }
/*      */     
/* 2643 */     MailItem.UnderlyingData data = item.getUnderlyingData().clone();
/* 2644 */     data.setFlag(Flag.FlagInfo.UNCACHED);
/* 2645 */     data.metadata = item.encodeMetadata().toString();
/* 2646 */     if ((item instanceof VirtualConversation))
/*      */     {
/* 2648 */       return new VirtualConversation(this, data);
/*      */     }
/* 2650 */     return MailItem.constructItem(this, data);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private FolderCache snapshotFolders()
/*      */     throws ServiceException
/*      */   {
/* 2668 */     if ((currentChange().depth > 1) || (this.mFolderCache == null)) {
/* 2669 */       return this.mFolderCache;
/*      */     }
/* 2671 */     return this.mFolderCache.makeCopy();
/*      */   }
/*      */   
/*      */ 
/* 2675 */   private static Set<MailItem.Type> FOLDER_TYPES = EnumSet.of(MailItem.Type.FOLDER, MailItem.Type.SEARCHFOLDER, MailItem.Type.MOUNTPOINT);
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private PendingModifications snapshotModifications(PendingModifications pms)
/*      */     throws ServiceException
/*      */   {
/* 2689 */     if (pms == null) {
/* 2690 */       return null;
/*      */     }
/* 2692 */     assert (currentChange().depth == 0);
/*      */     
/* 2694 */     ItemCache cache = (ItemCache)this.mItemCache.get();
/* 2695 */     FolderCache folders = (this.mFolderCache == null) || (Collections.disjoint(pms.changedTypes, FOLDER_TYPES)) ? this.mFolderCache : snapshotFolders();
/*      */     
/*      */ 
/* 2698 */     PendingModifications snapshot = new PendingModifications();
/*      */     
/* 2700 */     if ((pms.deleted != null) && (!pms.deleted.isEmpty())) {
/* 2701 */       snapshot.recordDeleted(pms.deleted);
/*      */     }
/*      */     
/* 2704 */     if ((pms.created != null) && (!pms.created.isEmpty())) {
/* 2705 */       for (MailItem item : pms.created.values()) {
/* 2706 */         if (((item instanceof Folder)) && (folders != null)) {
/* 2707 */           Folder folder = folders.get(item.getId());
/* 2708 */           if (folder == null) {
/* 2709 */             ZimbraLog.mailbox.warn("folder missing from snapshotted folder set: %d", new Object[] { Integer.valueOf(item.getId()) });
/* 2710 */             folder = (Folder)item;
/*      */           }
/* 2712 */           snapshot.recordCreated(folder);
/* 2713 */         } else if ((item instanceof Tag)) {
/* 2714 */           if (((Tag)item).isListed()) {
/* 2715 */             snapshot.recordCreated(snapshotItem(item));
/*      */           }
/*      */         }
/*      */         else {
/* 2719 */           if ((cache != null) && (cache.contains(item))) {
/* 2720 */             item = snapshotItem(item);
/*      */           }
/* 2722 */           snapshot.recordCreated(item);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 2727 */     if ((pms.modified != null) && (!pms.modified.isEmpty())) {
/* 2728 */       for (Map.Entry<PendingModifications.ModificationKey, PendingModifications.Change> entry : pms.modified.entrySet()) {
/* 2729 */         PendingModifications.Change chg = (PendingModifications.Change)entry.getValue();
/* 2730 */         if (!(chg.what instanceof MailItem)) {
/* 2731 */           snapshot.recordModified((PendingModifications.ModificationKey)entry.getKey(), chg);
/*      */         }
/*      */         else
/*      */         {
/* 2735 */           MailItem item = (MailItem)chg.what;
/* 2736 */           if (((item instanceof Folder)) && (folders != null)) {
/* 2737 */             Folder folder = folders.get(item.getId());
/* 2738 */             if (folder == null) {
/* 2739 */               ZimbraLog.mailbox.warn("folder missing from snapshotted folder set: %d", new Object[] { Integer.valueOf(item.getId()) });
/* 2740 */               folder = (Folder)item;
/*      */             }
/* 2742 */             snapshot.recordModified(folder, chg.why, (MailItem)chg.preModifyObj);
/* 2743 */           } else if ((item instanceof Tag)) {
/* 2744 */             if (((Tag)item).isListed()) {
/* 2745 */               snapshot.recordModified(snapshotItem(item), chg.why, (MailItem)chg.preModifyObj);
/*      */             }
/*      */           }
/*      */           else {
/* 2749 */             if ((cache != null) && (cache.contains(item))) {
/* 2750 */               item = snapshotItem(item);
/*      */             }
/* 2752 */             snapshot.recordModified(item, chg.why, (MailItem)chg.preModifyObj);
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/* 2757 */     return snapshot;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MailItem getItemById(OperationContext octxt, int id, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 2765 */     return getItemById(octxt, id, type, false);
/*      */   }
/*      */   
/*      */   public MailItem getItemById(OperationContext octxt, int id, MailItem.Type type, boolean fromDumpster) throws ServiceException
/*      */   {
/* 2770 */     boolean success = false;
/*      */     try
/*      */     {
/* 2773 */       beginReadTransaction("getItemById", octxt);
/* 2774 */       MailItem item = checkAccess(getItemById(id, type, fromDumpster));
/* 2775 */       success = true;
/* 2776 */       return item;
/*      */     } finally {
/* 2778 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   MailItem getItemById(int id, MailItem.Type type) throws ServiceException {
/* 2783 */     return getItemById(id, type, false);
/*      */   }
/*      */   
/*      */   private boolean isVisibleInDumpster(MailItem item)
/*      */     throws ServiceException
/*      */   {
/* 2789 */     OperationContext octxt = getOperationContext();
/* 2790 */     if (!hasFullAdminAccess(octxt)) {
/* 2791 */       long now = octxt != null ? octxt.getTimestamp() : System.currentTimeMillis();
/* 2792 */       long threshold = now - getAccount().getDumpsterUserVisibleAge();
/* 2793 */       if ((item.getChangeDate() < threshold) || (item.inSpam())) {
/* 2794 */         return false;
/*      */       }
/*      */     }
/* 2797 */     return true;
/*      */   }
/*      */   
/*      */   MailItem getItemById(int id, MailItem.Type type, boolean fromDumpster) throws ServiceException {
/* 2801 */     if (fromDumpster) {
/* 2802 */       MailItem item = null;
/*      */       try {
/* 2804 */         item = MailItem.getById(this, id, type, true);
/* 2805 */         if ((item != null) && (!isVisibleInDumpster(item))) {
/* 2806 */           item = null;
/*      */         }
/*      */       }
/*      */       catch (MailServiceException.NoSuchItemException e) {}
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 2814 */       if (item == null) {
/* 2815 */         throw MailItem.noSuchItem(id, type);
/*      */       }
/* 2817 */       return item;
/*      */     }
/*      */     
/*      */ 
/* 2821 */     MailItem item = getCachedItem(Integer.valueOf(id), type);
/* 2822 */     if (item != null) {
/* 2823 */       return item;
/*      */     }
/*      */     
/*      */ 
/* 2827 */     if (isCachedType(type)) {
/* 2828 */       throw MailItem.noSuchItem(id, type);
/*      */     }
/* 2830 */     boolean virtualConv = false;
/* 2831 */     boolean cachedMsg = true;
/* 2832 */     boolean sameId = true;
/* 2833 */     if (id <= 65280) {
/* 2834 */       virtualConv = true;
/* 2835 */       ZimbraLog.mailbox.debug("getting virtual conversation");
/*      */       
/* 2837 */       if ((type != MailItem.Type.CONVERSATION) && (type != MailItem.Type.UNKNOWN)) {
/* 2838 */         throw MailItem.noSuchItem(id, type);
/*      */       }
/* 2840 */       Message msg = getCachedMessage(Integer.valueOf(-id));
/* 2841 */       if (msg == null) {
/* 2842 */         ZimbraLog.mailbox.debug("message not cached");
/* 2843 */         cachedMsg = false;
/* 2844 */         msg = getMessageById(-id);
/*      */       }
/* 2846 */       int convId = msg.getConversationId();
/* 2847 */       if (msg.getConversationId() != id) {
/* 2848 */         ZimbraLog.mailbox.debug("message(%d) conv id(%d) != id(%d), getting parent", new Object[] { Integer.valueOf(msg.getId()), Integer.valueOf(msg.getConversationId()), Integer.valueOf(id) });
/* 2849 */         sameId = false;
/* 2850 */         item = msg.getParent();
/* 2851 */         if (item == null) {
/* 2852 */           ZimbraLog.mailbox.warn("got null parent for message id [%d] conv id [%d] (before condition [%d]) != id [%d]. equality? [%s:%s] in dumpster? [%s]", new Object[] { Integer.valueOf(msg.getId()), Integer.valueOf(msg.getConversationId()), Integer.valueOf(convId), Integer.valueOf(id), Boolean.valueOf(convId == id ? 1 : false), Boolean.valueOf(msg.getConversationId() == id ? 1 : false), Boolean.valueOf(msg.inDumpster()) });
/*      */         }
/*      */       } else {
/* 2855 */         ZimbraLog.mailbox.debug("returning normal virtual conv");
/* 2856 */         item = new VirtualConversation(this, msg);
/*      */       }
/*      */     }
/*      */     else {
/* 2860 */       item = MailItem.getById(this, id, type);
/*      */     }
/* 2862 */     if (item == null) {
/* 2863 */       ZimbraLog.mailbox.warn("item is null for id [%d] in mailbox [%d]. Virtual conv? [%s] cachedMsg? [%s] sameId? [%s]", new Object[] { Integer.valueOf(id), Integer.valueOf(this.mId), Boolean.valueOf(virtualConv), Boolean.valueOf(cachedMsg), Boolean.valueOf(sameId) });
/* 2864 */       throw MailItem.noSuchItem(id, type);
/*      */     }
/* 2866 */     return item;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MailItem getItemByUuid(OperationContext octxt, String uuid, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 2874 */     return getItemByUuid(octxt, uuid, type, false);
/*      */   }
/*      */   
/*      */   public MailItem getItemByUuid(OperationContext octxt, String uuid, MailItem.Type type, boolean fromDumpster) throws ServiceException
/*      */   {
/* 2879 */     boolean success = false;
/*      */     try
/*      */     {
/* 2882 */       beginReadTransaction("getItemByUuid", octxt);
/* 2883 */       MailItem item = checkAccess(getItemByUuid(uuid, type, fromDumpster));
/* 2884 */       success = true;
/* 2885 */       return item;
/*      */     } finally {
/* 2887 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   MailItem getItemByUuid(String uuid, MailItem.Type type) throws ServiceException {
/* 2892 */     return getItemByUuid(uuid, type, false);
/*      */   }
/*      */   
/*      */   MailItem getItemByUuid(String uuid, MailItem.Type type, boolean fromDumpster) throws ServiceException {
/* 2896 */     if (fromDumpster) {
/* 2897 */       MailItem item = null;
/*      */       try {
/* 2899 */         item = MailItem.getByUuid(this, uuid, type, true);
/* 2900 */         if ((item != null) && (!isVisibleInDumpster(item))) {
/* 2901 */           item = null;
/*      */         }
/*      */       }
/*      */       catch (MailServiceException.NoSuchItemException e) {}
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 2909 */       if (item == null) {
/* 2910 */         throw MailItem.noSuchItemUuid(uuid, type);
/*      */       }
/* 2912 */       return item;
/*      */     }
/*      */     
/*      */ 
/* 2916 */     MailItem item = getCachedItemByUuid(uuid, type);
/* 2917 */     if (item != null) {
/* 2918 */       return item;
/*      */     }
/*      */     
/*      */ 
/* 2922 */     if (isCachedType(type)) {
/* 2923 */       throw MailItem.noSuchItemUuid(uuid, type);
/*      */     }
/*      */     
/*      */ 
/* 2927 */     item = MailItem.getByUuid(this, uuid, type);
/*      */     
/* 2929 */     return item;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailItem[] getItemById(OperationContext octxt, Collection<Integer> ids, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 2938 */     return getItemById(octxt, ArrayUtil.toIntArray(ids), type);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MailItem[] getItemById(OperationContext octxt, int[] ids, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 2946 */     return getItemById(octxt, ids, type, false);
/*      */   }
/*      */   
/*      */   public MailItem[] getItemById(OperationContext octxt, int[] ids, MailItem.Type type, boolean fromDumpster) throws ServiceException
/*      */   {
/* 2951 */     boolean success = false;
/*      */     try
/*      */     {
/* 2954 */       beginTransaction("getItemById[]", octxt);
/* 2955 */       MailItem[] items = getItemById(ids, type, fromDumpster);
/*      */       
/* 2957 */       for (int i = 0; i < items.length; i++) {
/* 2958 */         checkAccess(items[i]);
/*      */       }
/* 2960 */       success = true;
/* 2961 */       return items;
/*      */     } finally {
/* 2963 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   MailItem[] getItemById(Collection<Integer> ids, MailItem.Type type) throws ServiceException {
/* 2968 */     return getItemById(ArrayUtil.toIntArray(ids), type);
/*      */   }
/*      */   
/*      */   MailItem[] getItemById(int[] ids, MailItem.Type type) throws ServiceException {
/* 2972 */     return getItemById(ids, type, false);
/*      */   }
/*      */   
/*      */   private MailItem[] getItemById(int[] ids, MailItem.Type type, boolean fromDumpster) throws ServiceException {
/* 2976 */     if (!currentChange().active) {
/* 2977 */       throw ServiceException.FAILURE("must be in transaction", null);
/*      */     }
/* 2979 */     if (ids == null) {
/* 2980 */       return null;
/*      */     }
/* 2982 */     MailItem[] items = new MailItem[ids.length];
/* 2983 */     if (fromDumpster) {
/* 2984 */       for (int i = 0; i < items.length; i++) {
/* 2985 */         int id = ids[i];
/* 2986 */         if (id > 0) {
/* 2987 */           items[i] = getItemById(id, type, true);
/*      */         }
/*      */       }
/* 2990 */       return items;
/*      */     }
/*      */     
/* 2993 */     Set<Integer> uncached = new HashSet();
/*      */     
/*      */ 
/* 2996 */     Integer miss = null;
/* 2997 */     boolean relaxType = false;
/* 2998 */     for (int i = 0; i < ids.length; i++)
/*      */     {
/* 3000 */       if (ids[i] == -1) {
/* 3001 */         items[i] = null;
/*      */       } else {
/* 3003 */         Integer key = Integer.valueOf(ids[i]);
/* 3004 */         MailItem item = getCachedItem(key, type);
/*      */         
/* 3006 */         if ((item == null) && (ids[i] <= 65280))
/*      */         {
/* 3008 */           if (!MailItem.isAcceptableType(type, MailItem.Type.CONVERSATION)) {
/* 3009 */             throw MailItem.noSuchItem(ids[i], type);
/*      */           }
/* 3011 */           Message msg = getCachedMessage(Integer.valueOf(-ids[i]));
/* 3012 */           if (msg != null) {
/* 3013 */             if (msg.getConversationId() == ids[i]) {
/* 3014 */               item = new VirtualConversation(this, msg);
/*      */             } else {
/* 3016 */               item = getCachedConversation(key = Integer.valueOf(msg.getConversationId()));
/*      */             }
/*      */           }
/*      */           else {
/* 3020 */             key = Integer.valueOf(-ids[i]);
/* 3021 */             relaxType = true;
/*      */           }
/*      */         }
/* 3024 */         items[i] = item;
/* 3025 */         if (item == null) {
/* 3026 */           uncached.add(miss = key);
/*      */         }
/*      */       }
/*      */     }
/* 3030 */     if (uncached.isEmpty()) {
/* 3031 */       return items;
/*      */     }
/*      */     
/*      */ 
/* 3035 */     if (isCachedType(type)) {
/* 3036 */       throw MailItem.noSuchItem(miss.intValue(), type);
/*      */     }
/*      */     
/*      */ 
/* 3040 */     List<MailItem> itemsFromDb = MailItem.getById(this, uncached, relaxType ? MailItem.Type.UNKNOWN : type);
/* 3041 */     HashMap<Integer, MailItem> tempCache = new HashMap();
/* 3042 */     for (MailItem item : itemsFromDb) {
/* 3043 */       tempCache.put(Integer.valueOf(item.getId()), item);
/*      */     }
/* 3045 */     uncached.clear();
/* 3046 */     Map<Integer, Integer> virtualConvsToRealConvs = new HashMap();
/* 3047 */     for (int i = 0; i < ids.length; i++) {
/* 3048 */       if ((ids[i] != -1) && (items[i] == null)) {
/* 3049 */         if (ids[i] <= 65280)
/*      */         {
/* 3051 */           MailItem item = (MailItem)tempCache.get(Integer.valueOf(-ids[i]));
/* 3052 */           if (!(item instanceof Message))
/* 3053 */             throw MailItem.noSuchItem(ids[i], type);
/* 3054 */           if (item.getParentId() == ids[i]) {
/* 3055 */             items[i] = new VirtualConversation(this, (Message)item);
/*      */           } else {
/* 3057 */             items[i] = ((MailItem)tempCache.get(Integer.valueOf(item.getParentId())));
/* 3058 */             if (items[i] == null) {
/* 3059 */               virtualConvsToRealConvs.put(Integer.valueOf(ids[i]), Integer.valueOf(item.getParentId()));
/*      */             }
/*      */           }
/*      */         }
/* 3063 */         else if ((items[i] = (MailItem)tempCache.get(Integer.valueOf(ids[i]))) == null) {
/* 3064 */           throw MailItem.noSuchItem(ids[i], type);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 3071 */     if (!virtualConvsToRealConvs.isEmpty()) {
/* 3072 */       itemsFromDb = MailItem.getById(this, virtualConvsToRealConvs.values(), MailItem.Type.CONVERSATION);
/* 3073 */       for (MailItem item : itemsFromDb) {
/* 3074 */         tempCache.put(Integer.valueOf(item.getId()), item);
/*      */       }
/* 3076 */       for (int i = 0; i < ids.length; i++) {
/* 3077 */         if ((ids[i] <= 65280) && (items[i] == null)) {
/* 3078 */           items[i] = ((MailItem)tempCache.get(virtualConvsToRealConvs.get(Integer.valueOf(ids[i]))));
/* 3079 */           if (items[i] == null) {
/* 3080 */             throw MailItem.noSuchItem(ids[i], type);
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 3086 */     return items;
/*      */   }
/*      */   
/*      */   MailItem getCachedItem(Integer key) throws ServiceException
/*      */   {
/* 3091 */     MailItem item = null;
/* 3092 */     if (key.intValue() < 0) {
/* 3093 */       item = Flag.of(this, key.intValue());
/*      */     }
/* 3095 */     if ((item == null) && (this.mTagCache != null)) {
/* 3096 */       item = (MailItem)this.mTagCache.get(key);
/*      */     }
/* 3098 */     if ((item == null) && (this.mFolderCache != null)) {
/* 3099 */       item = this.mFolderCache.get(key.intValue());
/*      */     }
/* 3101 */     if (item == null) {
/* 3102 */       item = getItemCache().get(key.intValue());
/*      */     }
/* 3104 */     logCacheActivity(key, item == null ? MailItem.Type.UNKNOWN : item.getType(), item);
/* 3105 */     return item;
/*      */   }
/*      */   
/*      */   MailItem getCachedItem(Integer key, MailItem.Type type) throws ServiceException {
/* 3109 */     MailItem item = null;
/* 3110 */     switch (type) {
/*      */     case UNKNOWN: 
/* 3112 */       return getCachedItem(key);
/*      */     case FLAG: 
/*      */     case TAG: 
/* 3115 */       if (key.intValue() < 0) {
/* 3116 */         item = Flag.of(this, key.intValue());
/* 3117 */       } else if (this.mTagCache != null) {
/* 3118 */         item = (MailItem)this.mTagCache.get(key);
/*      */       }
/*      */       break;
/*      */     case FOLDER: 
/*      */     case MOUNTPOINT: 
/*      */     case SEARCHFOLDER: 
/* 3124 */       if (this.mFolderCache != null) {
/* 3125 */         item = this.mFolderCache.get(key.intValue());
/*      */       }
/*      */       break;
/*      */     default: 
/* 3129 */       item = getItemCache().get(key.intValue());
/*      */     }
/*      */     
/*      */     
/* 3133 */     if ((item != null) && (!MailItem.isAcceptableType(type, MailItem.Type.of(item.mData.type)))) {
/* 3134 */       item = null;
/*      */     }
/*      */     
/* 3137 */     logCacheActivity(key, type, item);
/* 3138 */     return item;
/*      */   }
/*      */   
/*      */   MailItem getCachedItemByUuid(String uuid) throws ServiceException
/*      */   {
/* 3143 */     MailItem item = null;
/* 3144 */     if ((item == null) && (this.mFolderCache != null)) {
/* 3145 */       item = this.mFolderCache.get(uuid);
/*      */     }
/* 3147 */     if (item == null) {
/* 3148 */       item = getItemCache().get(uuid);
/*      */     }
/* 3150 */     logCacheActivity(uuid, item == null ? MailItem.Type.UNKNOWN : item.getType(), item);
/* 3151 */     return item;
/*      */   }
/*      */   
/*      */   MailItem getCachedItemByUuid(String uuid, MailItem.Type type) throws ServiceException {
/* 3155 */     MailItem item = null;
/* 3156 */     switch (type) {
/*      */     case UNKNOWN: 
/* 3158 */       return getCachedItemByUuid(uuid);
/*      */     case FOLDER: 
/*      */     case MOUNTPOINT: 
/*      */     case SEARCHFOLDER: 
/* 3162 */       if (this.mFolderCache != null) {
/* 3163 */         item = this.mFolderCache.get(uuid);
/*      */       }
/*      */       break;
/*      */     case FLAG: case TAG: default: 
/* 3167 */       item = getItemCache().get(uuid);
/*      */     }
/*      */     
/*      */     
/* 3171 */     if ((item != null) && (!MailItem.isAcceptableType(type, MailItem.Type.of(item.mData.type)))) {
/* 3172 */       item = null;
/*      */     }
/*      */     
/* 3175 */     logCacheActivity(uuid, type, item);
/* 3176 */     return item;
/*      */   }
/*      */   
/*      */   MailItem getItem(MailItem.UnderlyingData data) throws ServiceException
/*      */   {
/* 3181 */     if (data == null) {
/* 3182 */       return null;
/*      */     }
/* 3184 */     MailItem item = getCachedItem(Integer.valueOf(data.id), MailItem.Type.of(data.type));
/*      */     
/* 3186 */     if (item != null) {
/* 3187 */       return item;
/*      */     }
/* 3189 */     return MailItem.constructItem(this, data);
/*      */   }
/*      */   
/*      */   public MailItem getItemRevision(OperationContext octxt, int id, MailItem.Type type, int version) throws ServiceException
/*      */   {
/* 3194 */     return getItemRevision(octxt, id, type, version, false);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailItem getItemRevision(OperationContext octxt, int id, MailItem.Type type, int version, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 3205 */     boolean success = false;
/*      */     try {
/* 3207 */       beginTransaction("getItemRevision", octxt);
/* 3208 */       MailItem revision = checkAccess(getItemById(id, type, fromDumpster)).getRevision(version);
/* 3209 */       success = true;
/* 3210 */       return revision;
/*      */     } finally {
/* 3212 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public <T extends MailItem> List<T> getAllRevisions(OperationContext octxt, int id, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 3223 */     boolean success = false;
/*      */     try {
/* 3225 */       beginTransaction("getAllRevisions", octxt);
/* 3226 */       T item = checkAccess(getItemById(id, type));
/* 3227 */       List<MailItem> previousRevisions = item.loadRevisions();
/* 3228 */       List<T> result = new ArrayList(previousRevisions.size());
/* 3229 */       for (MailItem rev : previousRevisions) {
/* 3230 */         result.add(rev);
/*      */       }
/* 3232 */       result.add(item);
/*      */       
/* 3234 */       success = true;
/* 3235 */       return result;
/*      */     } finally {
/* 3237 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailItem getItemByImapId(OperationContext octxt, int imapId, int folderId)
/*      */     throws ServiceException
/*      */   {
/* 3247 */     boolean success = false;
/*      */     try
/*      */     {
/* 3250 */       beginTransaction("getItemByImapId", octxt);
/*      */       
/* 3252 */       MailItem item = checkAccess(getCachedItem(Integer.valueOf(imapId)));
/*      */       
/* 3254 */       if (item == null) {
/*      */         try {
/* 3256 */           item = checkAccess(MailItem.getById(this, imapId));
/* 3257 */           if (item.getImapUid() != imapId) {
/* 3258 */             item = null;
/*      */           }
/*      */         }
/*      */         catch (MailServiceException.NoSuchItemException nsie) {}
/*      */       }
/*      */       
/* 3264 */       if (item == null) {
/* 3265 */         item = checkAccess(MailItem.getByImapId(this, imapId, folderId));
/*      */       }
/* 3267 */       if ((isCachedType(item.getType())) || (item.getImapUid() != imapId) || (item.getFolderId() != folderId)) {
/* 3268 */         throw MailServiceException.NO_SUCH_ITEM(imapId);
/*      */       }
/* 3270 */       success = true;
/* 3271 */       return item;
/*      */     } finally {
/* 3273 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public MailItem getItemByPath(OperationContext octxt, String path)
/*      */     throws ServiceException
/*      */   {
/* 3280 */     return getItemByPath(octxt, path, 1);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailItem getItemByPath(OperationContext octxt, String name, int folderId)
/*      */     throws ServiceException
/*      */   {
/* 3290 */     if (name != null) {
/* 3291 */       while (name.startsWith("/")) {
/* 3292 */         folderId = 1;
/* 3293 */         name = name.substring(1);
/*      */       }
/* 3295 */       while (name.endsWith("/")) {
/* 3296 */         name = name.substring(0, name.length() - 1);
/*      */       }
/*      */     }
/* 3299 */     if (Strings.isNullOrEmpty(name)) {
/* 3300 */       return getFolderById(octxt, folderId);
/*      */     }
/* 3302 */     boolean success = false;
/*      */     try
/*      */     {
/* 3305 */       beginTransaction("getItemByPath", octxt);
/*      */       
/* 3307 */       Folder parent = (Folder)getItemById(folderId, MailItem.Type.FOLDER);
/*      */       
/* 3309 */       int slash = name.lastIndexOf('/');
/* 3310 */       if (slash != -1) {
/* 3311 */         for (String segment : name.substring(0, slash).split("/")) {
/* 3312 */           if ((parent = parent.findSubfolder(segment)) == null) {
/* 3313 */             throw MailServiceException.NO_SUCH_FOLDER(name);
/*      */           }
/*      */         }
/* 3316 */         name = name.substring(slash + 1);
/*      */       }
/*      */       
/* 3319 */       MailItem item = null;
/* 3320 */       if (folderId == 8) {
/* 3321 */         item = getTagByName(octxt, name);
/*      */       }
/*      */       else {
/* 3324 */         item = parent.findSubfolder(name);
/* 3325 */         if (item == null) {
/* 3326 */           item = getItem(DbMailItem.getByName(this, parent.getId(), name, MailItem.Type.DOCUMENT));
/*      */         }
/*      */       }
/*      */       
/* 3330 */       if (checkAccess(item) == null) {
/* 3331 */         throw MailServiceException.NO_SUCH_ITEM(name);
/*      */       }
/* 3333 */       success = true;
/* 3334 */       return item;
/*      */     } finally {
/* 3336 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<MailItem> getItemList(OperationContext octxt, MailItem.Type type) throws ServiceException
/*      */   {
/* 3342 */     return getItemList(octxt, type, -1);
/*      */   }
/*      */   
/*      */   public List<MailItem> getItemList(OperationContext octxt, MailItem.Type type, int folderId) throws ServiceException {
/* 3346 */     return getItemList(octxt, type, folderId, SortBy.NONE);
/*      */   }
/*      */   
/*      */   public List<MailItem> getItemList(OperationContext octxt, MailItem.Type type, int folderId, SortBy sort)
/*      */     throws ServiceException
/*      */   {
/* 3352 */     boolean success = false;
/*      */     
/* 3354 */     if (type == MailItem.Type.UNKNOWN) {
/* 3355 */       return Collections.emptyList();
/*      */     }
/*      */     List<MailItem> result;
/*      */     try {
/* 3359 */       beginReadTransaction("getItemList", octxt);
/*      */       
/* 3361 */       Folder folder = folderId == -1 ? null : getFolderById(folderId);
/* 3362 */       if (folder == null) {
/* 3363 */         if (!hasFullAccess()) {
/* 3364 */           throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */         }
/*      */       }
/* 3367 */       else if (!folder.canAccess((short)1, getAuthenticatedAccount(), isUsingAdminPrivileges())) {
/* 3368 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */       }
/*      */       
/*      */       Flag flag;
/* 3372 */       switch (type) {
/*      */       case FOLDER: 
/*      */       case MOUNTPOINT: 
/*      */       case SEARCHFOLDER: 
/* 3376 */         result = new ArrayList(this.mFolderCache.size());
/* 3377 */         for (Folder subfolder : this.mFolderCache.values()) {
/* 3378 */           if (((subfolder.getType() == type) || (type == MailItem.Type.FOLDER)) && (
/* 3379 */             (folder == null) || (subfolder.getFolderId() == folderId))) {
/* 3380 */             result.add(subfolder);
/*      */           }
/*      */         }
/*      */         
/* 3384 */         success = true;
/* 3385 */         break;
/*      */       case TAG: 
/* 3387 */         if ((folderId != -1) && (folderId != 8)) {
/* 3388 */           return Collections.emptyList();
/*      */         }
/* 3390 */         result = new ArrayList(this.mTagCache.size() / 2);
/* 3391 */         for (Map.Entry<Object, Tag> entry : this.mTagCache.entrySet()) {
/* 3392 */           Tag tag = (Tag)entry.getValue();
/* 3393 */           if (((entry.getKey() instanceof String)) && (tag.isListed())) {
/* 3394 */             result.add(tag);
/*      */           }
/*      */         }
/* 3397 */         success = true;
/* 3398 */         break;
/*      */       case FLAG: 
/* 3400 */         if ((folderId != -1) && (folderId != 8)) {
/* 3401 */           return Collections.emptyList();
/*      */         }
/* 3403 */         List<Flag> allFlags = Flag.allOf(this);
/* 3404 */         result = new ArrayList(allFlags.size());
/* 3405 */         for (Iterator i$ = allFlags.iterator(); i$.hasNext();) { flag = (Flag)i$.next();
/* 3406 */           result.add(flag);
/*      */         }
/* 3408 */         success = true;
/* 3409 */         break;
/*      */       default:  List<MailItem.UnderlyingData> dataList;
/*      */         List<MailItem.UnderlyingData> dataList;
/* 3412 */         if (folder != null) {
/* 3413 */           dataList = DbMailItem.getByFolder(folder, type, sort);
/*      */         } else {
/* 3415 */           dataList = DbMailItem.getByType(this, type, sort);
/*      */         }
/* 3417 */         if (dataList == null) {
/* 3418 */           return Collections.emptyList();
/*      */         }
/* 3420 */         result = new ArrayList(dataList.size());
/* 3421 */         for (MailItem.UnderlyingData data : dataList) {
/* 3422 */           if (data != null) {
/* 3423 */             result.add(getItem(data));
/*      */           }
/*      */         }
/*      */         
/* 3427 */         if (sort.getKey() == SortBy.Key.NAME_NATURAL_ORDER) {
/* 3428 */           sort = SortBy.NONE;
/*      */         }
/* 3430 */         success = true;
/*      */       }
/*      */     }
/*      */     finally {
/* 3434 */       endTransaction(success);
/*      */     }
/*      */     
/* 3437 */     Comparator<MailItem> comp = MailItem.getComparator(sort);
/* 3438 */     if (comp != null) {
/* 3439 */       Collections.sort(result, comp);
/*      */     }
/* 3441 */     return result;
/*      */   }
/*      */   
/*      */   public List<Integer> listItemIds(OperationContext octxt, MailItem.Type type, int folderId) throws ServiceException
/*      */   {
/* 3446 */     boolean success = false;
/*      */     try {
/* 3448 */       beginTransaction("listItemIds", octxt);
/* 3449 */       Folder folder = getFolderById(folderId);
/* 3450 */       List<Integer> ids = DbMailItem.listByFolder(folder, type, true);
/* 3451 */       success = true;
/* 3452 */       return ids;
/*      */     } finally {
/* 3454 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public TypedIdList getItemIds(OperationContext octxt, int folderId) throws ServiceException {
/* 3459 */     boolean success = false;
/*      */     try {
/* 3461 */       beginTransaction("listAllItemIds", octxt);
/* 3462 */       Folder folder = getFolderById(folderId);
/* 3463 */       TypedIdList ids = DbMailItem.listByFolder(folder, true);
/* 3464 */       success = true;
/* 3465 */       return ids;
/*      */     } finally {
/* 3467 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<ImapMessage> openImapFolder(OperationContext octxt, int folderId) throws ServiceException {
/* 3472 */     boolean success = false;
/*      */     try {
/* 3474 */       beginTransaction("openImapFolder", octxt);
/* 3475 */       Folder folder = getFolderById(folderId);
/* 3476 */       List<ImapMessage> i4list = DbMailItem.loadImapFolder(folder);
/* 3477 */       success = true;
/* 3478 */       return i4list;
/*      */     } finally {
/* 3480 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<Pop3Message> openPop3Folder(OperationContext octxt, Set<Integer> folderIds, Date popSince) throws ServiceException
/*      */   {
/* 3486 */     boolean success = false;
/*      */     try {
/* 3488 */       beginTransaction("openPop3Folder", octxt);
/* 3489 */       ImmutableSet.Builder<Folder> folders = ImmutableSet.builder();
/* 3490 */       for (Iterator i$ = folderIds.iterator(); i$.hasNext();) { folderId = ((Integer)i$.next()).intValue();
/* 3491 */         folders.add(getFolderById(folderId)); }
/*      */       int folderId;
/* 3493 */       List<Pop3Message> p3list = DbMailItem.loadPop3Folder(folders.build(), popSince);
/* 3494 */       success = true;
/* 3495 */       return p3list;
/*      */     } finally {
/* 3497 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public int getImapRecent(OperationContext octxt, int folderId) throws ServiceException {
/* 3502 */     boolean success = false;
/*      */     try {
/* 3504 */       beginTransaction("openImapFolder", octxt);
/* 3505 */       Folder folder = (Folder)checkAccess(getFolderById(folderId));
/* 3506 */       int recent = folder.getImapRECENT();
/* 3507 */       success = true;
/* 3508 */       return recent;
/*      */     } finally {
/* 3510 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void beginTrackingImap() throws ServiceException {
/* 3515 */     this.lock.lock();
/*      */     try {
/* 3517 */       if (isTrackingImap()) {
/*      */         return;
/*      */       }
/* 3520 */       TrackImap redoRecorder = new TrackImap(this.mId);
/* 3521 */       boolean success = false;
/*      */       try {
/* 3523 */         beginTransaction("beginTrackingImap", null, redoRecorder);
/* 3524 */         DbMailbox.startTrackingImap(this);
/* 3525 */         currentChange().imap = Boolean.TRUE;
/* 3526 */         success = true;
/*      */       } finally {
/* 3528 */         endTransaction(success);
/*      */       }
/*      */     } finally {
/* 3531 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public void beginTrackingSync() throws ServiceException {
/* 3536 */     this.lock.lock(false);
/*      */     try {
/* 3538 */       if (isTrackingSync()) {
/*      */         return;
/*      */       }
/*      */     } finally {
/* 3542 */       this.lock.release();
/*      */     }
/* 3544 */     this.lock.lock();
/*      */     try {
/* 3546 */       if (isTrackingSync()) {
/*      */         return;
/*      */       }
/* 3549 */       TrackSync redoRecorder = new TrackSync(this.mId);
/* 3550 */       boolean success = false;
/*      */       try {
/* 3552 */         beginTransaction("beginTrackingSync", null, redoRecorder);
/* 3553 */         currentChange().sync = Integer.valueOf(getLastChangeID());
/* 3554 */         DbMailbox.startTrackingSync(this);
/* 3555 */         success = true;
/*      */       } finally {
/* 3557 */         endTransaction(success);
/*      */       }
/*      */     } finally {
/* 3560 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public void recordImapSession(int folderId) throws ServiceException {
/* 3565 */     boolean success = false;
/*      */     try {
/* 3567 */       beginTransaction("recordImapSession", null);
/* 3568 */       getFolderById(folderId).checkpointRECENT();
/* 3569 */       success = true;
/*      */     } finally {
/* 3571 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public List<Integer> getTombstones(int lastSync, Set<MailItem.Type> types)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_0
/*      */     //   1: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   4: iconst_0
/*      */     //   5: invokevirtual 217	com/zimbra/cs/mailbox/MailboxLock:lock	(Z)V
/*      */     //   8: aload_0
/*      */     //   9: invokevirtual 692	com/zimbra/cs/mailbox/Mailbox:isTrackingSync	()Z
/*      */     //   12: ifne +11 -> 23
/*      */     //   15: ldc_w 699
/*      */     //   18: aconst_null
/*      */     //   19: invokestatic 63	com/zimbra/common/service/ServiceException:FAILURE	(Ljava/lang/String;Ljava/lang/Throwable;)Lcom/zimbra/common/service/ServiceException;
/*      */     //   22: athrow
/*      */     //   23: iload_1
/*      */     //   24: aload_0
/*      */     //   25: invokevirtual 160	com/zimbra/cs/mailbox/Mailbox:getSyncCutoff	()I
/*      */     //   28: if_icmpge +7 -> 35
/*      */     //   31: invokestatic 700	com/zimbra/cs/mailbox/MailServiceException:TOMBSTONES_EXPIRED	()Lcom/zimbra/common/service/ServiceException;
/*      */     //   34: athrow
/*      */     //   35: iconst_0
/*      */     //   36: istore_3
/*      */     //   37: aload_0
/*      */     //   38: ldc_w 701
/*      */     //   41: aconst_null
/*      */     //   42: invokevirtual 528	com/zimbra/cs/mailbox/Mailbox:beginReadTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;)V
/*      */     //   45: aload_0
/*      */     //   46: aload_0
/*      */     //   47: invokevirtual 292	com/zimbra/cs/mailbox/Mailbox:getOperationConnection	()Lcom/zimbra/cs/db/DbPool$DbConnection;
/*      */     //   50: iload_1
/*      */     //   51: i2l
/*      */     //   52: aload_2
/*      */     //   53: invokestatic 702	com/zimbra/cs/db/DbMailItem:readTombstones	(Lcom/zimbra/cs/mailbox/Mailbox;Lcom/zimbra/cs/db/DbPool$DbConnection;JLjava/util/Set;)Ljava/util/List;
/*      */     //   56: astore 4
/*      */     //   58: iconst_1
/*      */     //   59: istore_3
/*      */     //   60: aload 4
/*      */     //   62: astore 5
/*      */     //   64: aload_0
/*      */     //   65: iload_3
/*      */     //   66: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   69: aload_0
/*      */     //   70: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   73: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   76: aload 5
/*      */     //   78: areturn
/*      */     //   79: astore 6
/*      */     //   81: aload_0
/*      */     //   82: iload_3
/*      */     //   83: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   86: aload 6
/*      */     //   88: athrow
/*      */     //   89: astore 7
/*      */     //   91: aload_0
/*      */     //   92: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   95: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   98: aload 7
/*      */     //   100: athrow
/*      */     // Line number table:
/*      */     //   Java source line #3576	-> byte code offset #0
/*      */     //   Java source line #3578	-> byte code offset #8
/*      */     //   Java source line #3579	-> byte code offset #15
/*      */     //   Java source line #3580	-> byte code offset #23
/*      */     //   Java source line #3581	-> byte code offset #31
/*      */     //   Java source line #3584	-> byte code offset #35
/*      */     //   Java source line #3586	-> byte code offset #37
/*      */     //   Java source line #3587	-> byte code offset #45
/*      */     //   Java source line #3588	-> byte code offset #58
/*      */     //   Java source line #3589	-> byte code offset #60
/*      */     //   Java source line #3591	-> byte code offset #64
/*      */     //   Java source line #3594	-> byte code offset #69
/*      */     //   Java source line #3591	-> byte code offset #79
/*      */     //   Java source line #3594	-> byte code offset #89
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	101	0	this	Mailbox
/*      */     //   0	101	1	lastSync	int
/*      */     //   0	101	2	types	Set<MailItem.Type>
/*      */     //   36	47	3	success	boolean
/*      */     //   56	5	4	tombstones	List<Integer>
/*      */     //   62	15	5	localList1	List<Integer>
/*      */     //   79	8	6	localObject1	Object
/*      */     //   89	10	7	localObject2	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   37	64	79	finally
/*      */     //   79	81	79	finally
/*      */     //   8	69	89	finally
/*      */     //   79	91	89	finally
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public TypedIdList getTombstones(int lastSync)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_0
/*      */     //   1: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   4: iconst_0
/*      */     //   5: invokevirtual 217	com/zimbra/cs/mailbox/MailboxLock:lock	(Z)V
/*      */     //   8: aload_0
/*      */     //   9: invokevirtual 692	com/zimbra/cs/mailbox/Mailbox:isTrackingSync	()Z
/*      */     //   12: ifne +11 -> 23
/*      */     //   15: ldc_w 699
/*      */     //   18: aconst_null
/*      */     //   19: invokestatic 63	com/zimbra/common/service/ServiceException:FAILURE	(Ljava/lang/String;Ljava/lang/Throwable;)Lcom/zimbra/common/service/ServiceException;
/*      */     //   22: athrow
/*      */     //   23: iload_1
/*      */     //   24: aload_0
/*      */     //   25: invokevirtual 160	com/zimbra/cs/mailbox/Mailbox:getSyncCutoff	()I
/*      */     //   28: if_icmpge +7 -> 35
/*      */     //   31: invokestatic 700	com/zimbra/cs/mailbox/MailServiceException:TOMBSTONES_EXPIRED	()Lcom/zimbra/common/service/ServiceException;
/*      */     //   34: athrow
/*      */     //   35: iconst_0
/*      */     //   36: istore_2
/*      */     //   37: aload_0
/*      */     //   38: ldc_w 701
/*      */     //   41: aconst_null
/*      */     //   42: invokevirtual 528	com/zimbra/cs/mailbox/Mailbox:beginReadTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;)V
/*      */     //   45: aload_0
/*      */     //   46: iload_1
/*      */     //   47: i2l
/*      */     //   48: invokestatic 703	com/zimbra/cs/db/DbMailItem:readTombstones	(Lcom/zimbra/cs/mailbox/Mailbox;J)Lcom/zimbra/cs/mailbox/util/TypedIdList;
/*      */     //   51: astore_3
/*      */     //   52: iconst_1
/*      */     //   53: istore_2
/*      */     //   54: aload_3
/*      */     //   55: astore 4
/*      */     //   57: aload_0
/*      */     //   58: iload_2
/*      */     //   59: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   62: aload_0
/*      */     //   63: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   66: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   69: aload 4
/*      */     //   71: areturn
/*      */     //   72: astore 5
/*      */     //   74: aload_0
/*      */     //   75: iload_2
/*      */     //   76: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   79: aload 5
/*      */     //   81: athrow
/*      */     //   82: astore 6
/*      */     //   84: aload_0
/*      */     //   85: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   88: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   91: aload 6
/*      */     //   93: athrow
/*      */     // Line number table:
/*      */     //   Java source line #3599	-> byte code offset #0
/*      */     //   Java source line #3601	-> byte code offset #8
/*      */     //   Java source line #3602	-> byte code offset #15
/*      */     //   Java source line #3603	-> byte code offset #23
/*      */     //   Java source line #3604	-> byte code offset #31
/*      */     //   Java source line #3607	-> byte code offset #35
/*      */     //   Java source line #3609	-> byte code offset #37
/*      */     //   Java source line #3610	-> byte code offset #45
/*      */     //   Java source line #3611	-> byte code offset #52
/*      */     //   Java source line #3612	-> byte code offset #54
/*      */     //   Java source line #3614	-> byte code offset #57
/*      */     //   Java source line #3617	-> byte code offset #62
/*      */     //   Java source line #3614	-> byte code offset #72
/*      */     //   Java source line #3617	-> byte code offset #82
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	94	0	this	Mailbox
/*      */     //   0	94	1	lastSync	int
/*      */     //   36	40	2	success	boolean
/*      */     //   51	4	3	tombstones	TypedIdList
/*      */     //   55	15	4	localTypedIdList1	TypedIdList
/*      */     //   72	8	5	localObject1	Object
/*      */     //   82	10	6	localObject2	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   37	57	72	finally
/*      */     //   72	74	72	finally
/*      */     //   8	62	82	finally
/*      */     //   72	84	82	finally
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public List<Integer> getDumpsterItems(int lastSync, int folderId, int maxTrack)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_0
/*      */     //   1: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   4: iconst_0
/*      */     //   5: invokevirtual 217	com/zimbra/cs/mailbox/MailboxLock:lock	(Z)V
/*      */     //   8: iconst_0
/*      */     //   9: istore 4
/*      */     //   11: aload_0
/*      */     //   12: ldc_w 704
/*      */     //   15: aconst_null
/*      */     //   16: invokevirtual 528	com/zimbra/cs/mailbox/Mailbox:beginReadTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;)V
/*      */     //   19: aload_0
/*      */     //   20: iload_1
/*      */     //   21: iload_2
/*      */     //   22: iload_3
/*      */     //   23: invokestatic 705	com/zimbra/cs/db/DbMailItem:getDumpsterItems	(Lcom/zimbra/cs/mailbox/Mailbox;III)Ljava/util/List;
/*      */     //   26: astore 5
/*      */     //   28: iconst_1
/*      */     //   29: istore 4
/*      */     //   31: aload 5
/*      */     //   33: astore 6
/*      */     //   35: aload_0
/*      */     //   36: iload 4
/*      */     //   38: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   41: aload_0
/*      */     //   42: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   45: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   48: aload 6
/*      */     //   50: areturn
/*      */     //   51: astore 7
/*      */     //   53: aload_0
/*      */     //   54: iload 4
/*      */     //   56: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   59: aload 7
/*      */     //   61: athrow
/*      */     //   62: astore 8
/*      */     //   64: aload_0
/*      */     //   65: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   68: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   71: aload 8
/*      */     //   73: athrow
/*      */     // Line number table:
/*      */     //   Java source line #3622	-> byte code offset #0
/*      */     //   Java source line #3624	-> byte code offset #8
/*      */     //   Java source line #3626	-> byte code offset #11
/*      */     //   Java source line #3627	-> byte code offset #19
/*      */     //   Java source line #3628	-> byte code offset #28
/*      */     //   Java source line #3629	-> byte code offset #31
/*      */     //   Java source line #3631	-> byte code offset #35
/*      */     //   Java source line #3634	-> byte code offset #41
/*      */     //   Java source line #3631	-> byte code offset #51
/*      */     //   Java source line #3634	-> byte code offset #62
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	74	0	this	Mailbox
/*      */     //   0	74	1	lastSync	int
/*      */     //   0	74	2	folderId	int
/*      */     //   0	74	3	maxTrack	int
/*      */     //   9	46	4	success	boolean
/*      */     //   26	6	5	items	List<Integer>
/*      */     //   33	16	6	localList1	List<Integer>
/*      */     //   51	9	7	localObject1	Object
/*      */     //   62	10	8	localObject2	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   11	35	51	finally
/*      */     //   51	53	51	finally
/*      */     //   8	41	62	finally
/*      */     //   51	64	62	finally
/*      */   }
/*      */   
/*      */   public List<Folder> getModifiedFolders(int lastSync)
/*      */     throws ServiceException
/*      */   {
/* 3639 */     return getModifiedFolders(lastSync, MailItem.Type.UNKNOWN);
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public List<Folder> getModifiedFolders(int lastSync, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_0
/*      */     //   1: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   4: iconst_0
/*      */     //   5: invokevirtual 217	com/zimbra/cs/mailbox/MailboxLock:lock	(Z)V
/*      */     //   8: iload_1
/*      */     //   9: aload_0
/*      */     //   10: invokevirtual 176	com/zimbra/cs/mailbox/Mailbox:getLastChangeID	()I
/*      */     //   13: if_icmplt +16 -> 29
/*      */     //   16: invokestatic 118	java/util/Collections:emptyList	()Ljava/util/List;
/*      */     //   19: astore_3
/*      */     //   20: aload_0
/*      */     //   21: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   24: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   27: aload_3
/*      */     //   28: areturn
/*      */     //   29: new 119	java/util/ArrayList
/*      */     //   32: dup
/*      */     //   33: invokespecial 370	java/util/ArrayList:<init>	()V
/*      */     //   36: astore_3
/*      */     //   37: iconst_0
/*      */     //   38: istore 4
/*      */     //   40: aload_0
/*      */     //   41: ldc_w 707
/*      */     //   44: aconst_null
/*      */     //   45: invokevirtual 528	com/zimbra/cs/mailbox/Mailbox:beginReadTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;)V
/*      */     //   48: aload_0
/*      */     //   49: bipush 11
/*      */     //   51: invokevirtual 661	com/zimbra/cs/mailbox/Mailbox:getFolderById	(I)Lcom/zimbra/cs/mailbox/Folder;
/*      */     //   54: invokevirtual 708	com/zimbra/cs/mailbox/Folder:getSubfolderHierarchy	()Ljava/util/List;
/*      */     //   57: invokeinterface 123 1 0
/*      */     //   62: astore 5
/*      */     //   64: aload 5
/*      */     //   66: invokeinterface 124 1 0
/*      */     //   71: ifeq +52 -> 123
/*      */     //   74: aload 5
/*      */     //   76: invokeinterface 125 1 0
/*      */     //   81: checkcast 351	com/zimbra/cs/mailbox/Folder
/*      */     //   84: astore 6
/*      */     //   86: aload_2
/*      */     //   87: getstatic 390	com/zimbra/cs/mailbox/MailItem$Type:UNKNOWN	Lcom/zimbra/cs/mailbox/MailItem$Type;
/*      */     //   90: if_acmpeq +12 -> 102
/*      */     //   93: aload 6
/*      */     //   95: invokevirtual 664	com/zimbra/cs/mailbox/Folder:getType	()Lcom/zimbra/cs/mailbox/MailItem$Type;
/*      */     //   98: aload_2
/*      */     //   99: if_acmpne +21 -> 120
/*      */     //   102: aload 6
/*      */     //   104: invokevirtual 709	com/zimbra/cs/mailbox/Folder:getModifiedSequence	()I
/*      */     //   107: iload_1
/*      */     //   108: if_icmple +12 -> 120
/*      */     //   111: aload_3
/*      */     //   112: aload 6
/*      */     //   114: invokeinterface 128 2 0
/*      */     //   119: pop
/*      */     //   120: goto -56 -> 64
/*      */     //   123: iconst_1
/*      */     //   124: istore 4
/*      */     //   126: aload_3
/*      */     //   127: astore 5
/*      */     //   129: aload_0
/*      */     //   130: iload 4
/*      */     //   132: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   135: aload_0
/*      */     //   136: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   139: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   142: aload 5
/*      */     //   144: areturn
/*      */     //   145: astore 7
/*      */     //   147: aload_0
/*      */     //   148: iload 4
/*      */     //   150: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   153: aload 7
/*      */     //   155: athrow
/*      */     //   156: astore 8
/*      */     //   158: aload_0
/*      */     //   159: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   162: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   165: aload 8
/*      */     //   167: athrow
/*      */     // Line number table:
/*      */     //   Java source line #3643	-> byte code offset #0
/*      */     //   Java source line #3645	-> byte code offset #8
/*      */     //   Java source line #3646	-> byte code offset #16
/*      */     //   Java source line #3666	-> byte code offset #20
/*      */     //   Java source line #3649	-> byte code offset #29
/*      */     //   Java source line #3650	-> byte code offset #37
/*      */     //   Java source line #3652	-> byte code offset #40
/*      */     //   Java source line #3653	-> byte code offset #48
/*      */     //   Java source line #3654	-> byte code offset #86
/*      */     //   Java source line #3655	-> byte code offset #102
/*      */     //   Java source line #3656	-> byte code offset #111
/*      */     //   Java source line #3659	-> byte code offset #120
/*      */     //   Java source line #3660	-> byte code offset #123
/*      */     //   Java source line #3661	-> byte code offset #126
/*      */     //   Java source line #3663	-> byte code offset #129
/*      */     //   Java source line #3666	-> byte code offset #135
/*      */     //   Java source line #3663	-> byte code offset #145
/*      */     //   Java source line #3666	-> byte code offset #156
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	168	0	this	Mailbox
/*      */     //   0	168	1	lastSync	int
/*      */     //   0	168	2	type	MailItem.Type
/*      */     //   19	9	3	localList	List
/*      */     //   36	91	3	modified	Object
/*      */     //   38	111	4	success	boolean
/*      */     //   62	81	5	i$	Iterator
/*      */     //   84	29	6	subfolder	Folder
/*      */     //   145	9	7	localObject1	Object
/*      */     //   156	10	8	localObject2	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   40	129	145	finally
/*      */     //   145	147	145	finally
/*      */     //   8	20	156	finally
/*      */     //   29	135	156	finally
/*      */     //   145	158	156	finally
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public List<Tag> getModifiedTags(OperationContext octxt, int lastSync)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_0
/*      */     //   1: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   4: iconst_0
/*      */     //   5: invokevirtual 217	com/zimbra/cs/mailbox/MailboxLock:lock	(Z)V
/*      */     //   8: iload_2
/*      */     //   9: aload_0
/*      */     //   10: invokevirtual 176	com/zimbra/cs/mailbox/Mailbox:getLastChangeID	()I
/*      */     //   13: if_icmplt +16 -> 29
/*      */     //   16: invokestatic 118	java/util/Collections:emptyList	()Ljava/util/List;
/*      */     //   19: astore_3
/*      */     //   20: aload_0
/*      */     //   21: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   24: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   27: aload_3
/*      */     //   28: areturn
/*      */     //   29: new 119	java/util/ArrayList
/*      */     //   32: dup
/*      */     //   33: invokespecial 370	java/util/ArrayList:<init>	()V
/*      */     //   36: astore_3
/*      */     //   37: iconst_0
/*      */     //   38: istore 4
/*      */     //   40: aload_0
/*      */     //   41: ldc_w 710
/*      */     //   44: aload_1
/*      */     //   45: invokevirtual 528	com/zimbra/cs/mailbox/Mailbox:beginReadTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;)V
/*      */     //   48: aload_0
/*      */     //   49: invokevirtual 315	com/zimbra/cs/mailbox/Mailbox:hasFullAccess	()Z
/*      */     //   52: ifeq +95 -> 147
/*      */     //   55: aload_0
/*      */     //   56: getfield 347	com/zimbra/cs/mailbox/Mailbox:mTagCache	Ljava/util/Map;
/*      */     //   59: invokeinterface 470 1 0
/*      */     //   64: invokeinterface 418 1 0
/*      */     //   69: astore 5
/*      */     //   71: aload 5
/*      */     //   73: invokeinterface 124 1 0
/*      */     //   78: ifeq +69 -> 147
/*      */     //   81: aload 5
/*      */     //   83: invokeinterface 125 1 0
/*      */     //   88: checkcast 445	java/util/Map$Entry
/*      */     //   91: astore 6
/*      */     //   93: aload 6
/*      */     //   95: invokeinterface 446 1 0
/*      */     //   100: instanceof 471
/*      */     //   103: ifeq +41 -> 144
/*      */     //   106: aload 6
/*      */     //   108: invokeinterface 448 1 0
/*      */     //   113: checkcast 346	com/zimbra/cs/mailbox/Tag
/*      */     //   116: astore 7
/*      */     //   118: aload 7
/*      */     //   120: invokevirtual 555	com/zimbra/cs/mailbox/Tag:isListed	()Z
/*      */     //   123: ifeq +21 -> 144
/*      */     //   126: aload 7
/*      */     //   128: invokevirtual 711	com/zimbra/cs/mailbox/Tag:getModifiedSequence	()I
/*      */     //   131: iload_2
/*      */     //   132: if_icmple +12 -> 144
/*      */     //   135: aload_3
/*      */     //   136: aload 7
/*      */     //   138: invokeinterface 128 2 0
/*      */     //   143: pop
/*      */     //   144: goto -73 -> 71
/*      */     //   147: iconst_1
/*      */     //   148: istore 4
/*      */     //   150: aload_3
/*      */     //   151: astore 5
/*      */     //   153: aload_0
/*      */     //   154: iload 4
/*      */     //   156: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   159: aload_0
/*      */     //   160: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   163: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   166: aload 5
/*      */     //   168: areturn
/*      */     //   169: astore 8
/*      */     //   171: aload_0
/*      */     //   172: iload 4
/*      */     //   174: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   177: aload 8
/*      */     //   179: athrow
/*      */     //   180: astore 9
/*      */     //   182: aload_0
/*      */     //   183: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   186: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   189: aload 9
/*      */     //   191: athrow
/*      */     // Line number table:
/*      */     //   Java source line #3671	-> byte code offset #0
/*      */     //   Java source line #3673	-> byte code offset #8
/*      */     //   Java source line #3674	-> byte code offset #16
/*      */     //   Java source line #3696	-> byte code offset #20
/*      */     //   Java source line #3676	-> byte code offset #29
/*      */     //   Java source line #3677	-> byte code offset #37
/*      */     //   Java source line #3679	-> byte code offset #40
/*      */     //   Java source line #3680	-> byte code offset #48
/*      */     //   Java source line #3681	-> byte code offset #55
/*      */     //   Java source line #3682	-> byte code offset #93
/*      */     //   Java source line #3683	-> byte code offset #106
/*      */     //   Java source line #3684	-> byte code offset #118
/*      */     //   Java source line #3685	-> byte code offset #135
/*      */     //   Java source line #3688	-> byte code offset #144
/*      */     //   Java source line #3690	-> byte code offset #147
/*      */     //   Java source line #3691	-> byte code offset #150
/*      */     //   Java source line #3693	-> byte code offset #153
/*      */     //   Java source line #3696	-> byte code offset #159
/*      */     //   Java source line #3693	-> byte code offset #169
/*      */     //   Java source line #3696	-> byte code offset #180
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	192	0	this	Mailbox
/*      */     //   0	192	1	octxt	OperationContext
/*      */     //   0	192	2	lastSync	int
/*      */     //   19	9	3	localList	List
/*      */     //   36	115	3	modified	Object
/*      */     //   38	135	4	success	boolean
/*      */     //   69	98	5	i$	Iterator
/*      */     //   91	16	6	entry	Map.Entry<Object, Tag>
/*      */     //   116	21	7	tag	Tag
/*      */     //   169	9	8	localObject1	Object
/*      */     //   180	10	9	localObject2	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   40	153	169	finally
/*      */     //   169	171	169	finally
/*      */     //   8	20	180	finally
/*      */     //   29	159	180	finally
/*      */     //   169	182	180	finally
/*      */   }
/*      */   
/*      */   public Pair<List<Integer>, TypedIdList> getModifiedItems(OperationContext octxt, int lastSync)
/*      */     throws ServiceException
/*      */   {
/* 3716 */     return getModifiedItems(octxt, lastSync, MailItem.Type.UNKNOWN, null);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Pair<List<Integer>, TypedIdList> getModifiedItems(OperationContext octxt, int lastSync, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 3739 */     return getModifiedItems(octxt, lastSync, type, null);
/*      */   }
/*      */   
/*      */   public Pair<List<Integer>, TypedIdList> getModifiedItems(OperationContext octxt, int lastSync, MailItem.Type type, Set<Integer> folderIds) throws ServiceException
/*      */   {
/* 3744 */     return getModifiedItems(octxt, lastSync, 0, type, folderIds);
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public Pair<List<Integer>, TypedIdList> getModifiedItems(OperationContext octxt, int lastSync, int sinceDate, MailItem.Type type, Set<Integer> folderIds)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_0
/*      */     //   1: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   4: iconst_0
/*      */     //   5: invokevirtual 217	com/zimbra/cs/mailbox/MailboxLock:lock	(Z)V
/*      */     //   8: iload_2
/*      */     //   9: aload_0
/*      */     //   10: invokevirtual 176	com/zimbra/cs/mailbox/Mailbox:getLastChangeID	()I
/*      */     //   13: if_icmplt +32 -> 45
/*      */     //   16: new 329	com/zimbra/common/util/Pair
/*      */     //   19: dup
/*      */     //   20: invokestatic 118	java/util/Collections:emptyList	()Ljava/util/List;
/*      */     //   23: new 714	com/zimbra/cs/mailbox/util/TypedIdList
/*      */     //   26: dup
/*      */     //   27: invokespecial 715	com/zimbra/cs/mailbox/util/TypedIdList:<init>	()V
/*      */     //   30: invokespecial 330	com/zimbra/common/util/Pair:<init>	(Ljava/lang/Object;Ljava/lang/Object;)V
/*      */     //   33: astore 6
/*      */     //   35: aload_0
/*      */     //   36: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   39: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   42: aload 6
/*      */     //   44: areturn
/*      */     //   45: iconst_0
/*      */     //   46: istore 6
/*      */     //   48: aload_0
/*      */     //   49: ldc_w 716
/*      */     //   52: aload_1
/*      */     //   53: invokevirtual 528	com/zimbra/cs/mailbox/Mailbox:beginReadTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;)V
/*      */     //   56: aload_0
/*      */     //   57: iconst_1
/*      */     //   58: invokevirtual 717	com/zimbra/cs/mailbox/Mailbox:getAccessibleFolders	(S)Ljava/util/Set;
/*      */     //   61: invokestatic 718	com/zimbra/cs/mailbox/Folder:toId	(Ljava/util/Set;)Ljava/util/Set;
/*      */     //   64: astore 7
/*      */     //   66: aload 5
/*      */     //   68: ifnonnull +10 -> 78
/*      */     //   71: aload 7
/*      */     //   73: astore 5
/*      */     //   75: goto +17 -> 92
/*      */     //   78: aload 7
/*      */     //   80: ifnull +12 -> 92
/*      */     //   83: aload 5
/*      */     //   85: aload 7
/*      */     //   87: invokestatic 719	com/zimbra/common/util/SetUtil:intersect	(Ljava/util/Set;Ljava/util/Set;)Ljava/util/Set;
/*      */     //   90: astore 5
/*      */     //   92: aload_0
/*      */     //   93: aload 4
/*      */     //   95: iload_2
/*      */     //   96: i2l
/*      */     //   97: iload_3
/*      */     //   98: aload 5
/*      */     //   100: invokestatic 720	com/zimbra/cs/db/DbMailItem:getModifiedItems	(Lcom/zimbra/cs/mailbox/Mailbox;Lcom/zimbra/cs/mailbox/MailItem$Type;JILjava/util/Set;)Lcom/zimbra/common/util/Pair;
/*      */     //   103: astore 8
/*      */     //   105: aload 8
/*      */     //   107: ifnonnull +22 -> 129
/*      */     //   110: aconst_null
/*      */     //   111: astore 9
/*      */     //   113: aload_0
/*      */     //   114: iload 6
/*      */     //   116: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   119: aload_0
/*      */     //   120: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   123: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   126: aload 9
/*      */     //   128: areturn
/*      */     //   129: iconst_1
/*      */     //   130: istore 6
/*      */     //   132: aload 8
/*      */     //   134: astore 9
/*      */     //   136: aload_0
/*      */     //   137: iload 6
/*      */     //   139: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   142: aload_0
/*      */     //   143: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   146: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   149: aload 9
/*      */     //   151: areturn
/*      */     //   152: astore 10
/*      */     //   154: aload_0
/*      */     //   155: iload 6
/*      */     //   157: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   160: aload 10
/*      */     //   162: athrow
/*      */     //   163: astore 11
/*      */     //   165: aload_0
/*      */     //   166: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   169: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   172: aload 11
/*      */     //   174: athrow
/*      */     // Line number table:
/*      */     //   Java source line #3762	-> byte code offset #0
/*      */     //   Java source line #3764	-> byte code offset #8
/*      */     //   Java source line #3765	-> byte code offset #16
/*      */     //   Java source line #3788	-> byte code offset #35
/*      */     //   Java source line #3767	-> byte code offset #45
/*      */     //   Java source line #3769	-> byte code offset #48
/*      */     //   Java source line #3771	-> byte code offset #56
/*      */     //   Java source line #3772	-> byte code offset #66
/*      */     //   Java source line #3773	-> byte code offset #71
/*      */     //   Java source line #3774	-> byte code offset #78
/*      */     //   Java source line #3775	-> byte code offset #83
/*      */     //   Java source line #3777	-> byte code offset #92
/*      */     //   Java source line #3779	-> byte code offset #105
/*      */     //   Java source line #3780	-> byte code offset #110
/*      */     //   Java source line #3785	-> byte code offset #113
/*      */     //   Java source line #3788	-> byte code offset #119
/*      */     //   Java source line #3782	-> byte code offset #129
/*      */     //   Java source line #3783	-> byte code offset #132
/*      */     //   Java source line #3785	-> byte code offset #136
/*      */     //   Java source line #3788	-> byte code offset #142
/*      */     //   Java source line #3785	-> byte code offset #152
/*      */     //   Java source line #3788	-> byte code offset #163
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	175	0	this	Mailbox
/*      */     //   0	175	1	octxt	OperationContext
/*      */     //   0	175	2	lastSync	int
/*      */     //   0	175	3	sinceDate	int
/*      */     //   0	175	4	type	MailItem.Type
/*      */     //   0	175	5	folderIds	Set<Integer>
/*      */     //   33	10	6	localPair	Pair
/*      */     //   46	110	6	success	boolean
/*      */     //   64	22	7	visible	Set<Integer>
/*      */     //   103	30	8	dataList	Pair<List<Integer>, TypedIdList>
/*      */     //   111	39	9	localPair1	Pair<List<Integer>, TypedIdList>
/*      */     //   152	9	10	localObject1	Object
/*      */     //   163	10	11	localObject2	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   48	113	152	finally
/*      */     //   129	136	152	finally
/*      */     //   152	154	152	finally
/*      */     //   8	35	163	finally
/*      */     //   45	119	163	finally
/*      */     //   129	142	163	finally
/*      */     //   152	165	163	finally
/*      */   }
/*      */   
/*      */   public Set<Folder> getVisibleFolders(OperationContext octxt)
/*      */     throws ServiceException
/*      */   {
/* 3799 */     boolean success = false;
/*      */     try {
/* 3801 */       beginReadTransaction("getVisibleFolders", octxt);
/* 3802 */       Set<Folder> visible = getAccessibleFolders((short)1);
/* 3803 */       success = true;
/* 3804 */       return visible;
/*      */     } finally {
/* 3806 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   Set<Folder> getAccessibleFolders(short rights)
/*      */     throws ServiceException
/*      */   {
/* 3817 */     if (!currentChange().isActive()) {
/* 3818 */       throw ServiceException.FAILURE("cannot get visible hierarchy outside transaction", null);
/*      */     }
/* 3820 */     if (hasFullAccess()) {
/* 3821 */       return null;
/*      */     }
/* 3823 */     boolean incomplete = false;
/* 3824 */     Set<Folder> visible = new HashSet();
/* 3825 */     for (Folder folder : this.mFolderCache.values()) {
/* 3826 */       if (folder.canAccess(rights)) {
/* 3827 */         visible.add(folder);
/*      */       } else {
/* 3829 */         incomplete = true;
/*      */       }
/*      */     }
/* 3832 */     return incomplete ? visible : null;
/*      */   }
/*      */   
/*      */   public Flag getFlagById(int flagId) throws ServiceException {
/* 3836 */     Flag flag = Flag.of(this, flagId);
/* 3837 */     if (flag == null) {
/* 3838 */       throw MailServiceException.NO_SUCH_TAG(flagId);
/*      */     }
/* 3840 */     return flag;
/*      */   }
/*      */   
/*      */   public List<Flag> getFlagList() throws ServiceException {
/* 3844 */     return Flag.allOf(this);
/*      */   }
/*      */   
/*      */   public Tag getTagById(OperationContext octxt, int id) throws ServiceException {
/* 3848 */     return (Tag)getItemById(octxt, id, MailItem.Type.TAG);
/*      */   }
/*      */   
/*      */   Tag getTagById(int id) throws ServiceException {
/* 3852 */     return (Tag)getItemById(id, MailItem.Type.TAG);
/*      */   }
/*      */   
/*      */   public List<Tag> getTagList(OperationContext octxt) throws ServiceException {
/* 3856 */     List<Tag> tags = new ArrayList();
/* 3857 */     for (MailItem item : getItemList(octxt, MailItem.Type.TAG)) {
/* 3858 */       tags.add((Tag)item);
/*      */     }
/* 3860 */     return tags;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Tag getTagByName(OperationContext octxt, String name)
/*      */     throws ServiceException
/*      */   {
/* 3873 */     if (Strings.isNullOrEmpty(name)) {
/* 3874 */       throw ServiceException.INVALID_REQUEST("tag name may not be null", null);
/*      */     }
/*      */     
/* 3877 */     boolean success = false;
/*      */     try {
/* 3879 */       beginReadTransaction("getTagByName", octxt);
/* 3880 */       if (!hasFullAccess()) {
/* 3881 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */       }
/*      */       
/* 3884 */       Tag tag = (Tag)checkAccess(getTagByName(name));
/* 3885 */       success = true;
/* 3886 */       return tag;
/*      */     } finally {
/* 3888 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   Tag getTagByName(String name) throws ServiceException {
/* 3893 */     Tag tag = name.startsWith("\\") ? Flag.of(this, name) : (Tag)this.mTagCache.get(name.toLowerCase());
/* 3894 */     if (tag == null) {
/* 3895 */       throw MailServiceException.NO_SUCH_TAG(name);
/*      */     }
/* 3897 */     return tag;
/*      */   }
/*      */   
/*      */   public Folder getFolderById(OperationContext octxt, int id)
/*      */     throws ServiceException
/*      */   {
/* 3903 */     return (Folder)getItemById(octxt, id, MailItem.Type.FOLDER);
/*      */   }
/*      */   
/*      */   Folder getFolderById(int id)
/*      */     throws ServiceException
/*      */   {
/* 3909 */     return (Folder)getItemById(id, MailItem.Type.FOLDER);
/*      */   }
/*      */   
/*      */   public Folder getFolderByUuid(OperationContext octxt, String uuid)
/*      */     throws ServiceException
/*      */   {
/* 3915 */     return (Folder)getItemByUuid(octxt, uuid, MailItem.Type.FOLDER);
/*      */   }
/*      */   
/*      */   Folder getFolderByUuid(String uuid)
/*      */     throws ServiceException
/*      */   {
/* 3921 */     return (Folder)getItemByUuid(uuid, MailItem.Type.FOLDER);
/*      */   }
/*      */   
/*      */   public Folder getFolderByName(OperationContext octxt, int parentId, String name)
/*      */     throws ServiceException
/*      */   {
/* 3927 */     boolean success = false;
/*      */     try {
/* 3929 */       beginReadTransaction("getFolderByName", octxt);
/* 3930 */       Folder folder = getFolderById(parentId).findSubfolder(name);
/* 3931 */       if (folder == null)
/* 3932 */         throw MailServiceException.NO_SUCH_FOLDER(name);
/* 3933 */       if (!folder.canAccess((short)1)) {
/* 3934 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions on folder " + name);
/*      */       }
/* 3936 */       success = true;
/* 3937 */       return folder;
/*      */     } finally {
/* 3939 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Folder getFolderByPath(OperationContext octxt, String path)
/*      */     throws ServiceException
/*      */   {
/* 3946 */     if (path == null) {
/* 3947 */       throw MailServiceException.NO_SUCH_FOLDER(path);
/*      */     }
/*      */     
/* 3950 */     while (path.startsWith("/")) {
/* 3951 */       path = path.substring(1);
/*      */     }
/* 3953 */     while (path.endsWith("/")) {
/* 3954 */       path = path.substring(0, path.length() - 1);
/*      */     }
/*      */     
/* 3957 */     Folder folder = getFolderById(null, 1);
/*      */     
/* 3959 */     boolean success = false;
/*      */     try {
/* 3961 */       beginReadTransaction("getFolderByPath", octxt);
/* 3962 */       if (!path.isEmpty()) {
/* 3963 */         for (String segment : path.split("/")) {
/* 3964 */           if ((folder = folder.findSubfolder(segment)) == null) {
/*      */             break;
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 3970 */       if (folder == null)
/* 3971 */         throw MailServiceException.NO_SUCH_FOLDER("/" + path);
/* 3972 */       if (!folder.canAccess((short)1)) {
/* 3973 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions on folder /" + path);
/*      */       }
/* 3975 */       success = true;
/* 3976 */       return folder;
/*      */     } finally {
/* 3978 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Pair<Folder, String> getFolderByPathLongestMatch(OperationContext octxt, int baseFolderId, String path)
/*      */     throws ServiceException
/*      */   {
/* 3997 */     if (Strings.isNullOrEmpty(path)) {
/* 3998 */       throw MailServiceException.NO_SUCH_FOLDER(path);
/*      */     }
/* 4000 */     Folder folder = getFolderById(null, baseFolderId);
/* 4001 */     assert (folder != null);
/* 4002 */     path = CharMatcher.is('/').trimFrom(path);
/* 4003 */     if (path.isEmpty()) {
/* 4004 */       return new Pair(checkAccess(folder), null);
/*      */     }
/*      */     
/* 4007 */     boolean success = false;
/*      */     try {
/* 4009 */       beginReadTransaction("getFolderByPathLongestMatch", octxt);
/* 4010 */       String unmatched = null;
/* 4011 */       String[] segments = path.split("/");
/* 4012 */       for (int i = 0; i < segments.length; i++) {
/* 4013 */         Folder subfolder = folder.findSubfolder(segments[i]);
/* 4014 */         if (subfolder == null) {
/* 4015 */           unmatched = StringUtil.join("/", segments, i, segments.length - i);
/* 4016 */           break;
/*      */         }
/* 4018 */         folder = subfolder;
/*      */       }
/*      */       
/* 4021 */       return new Pair(checkAccess(folder), unmatched);
/*      */     } finally {
/* 4023 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<Folder> getFolderList(OperationContext octxt, SortBy sort) throws ServiceException {
/* 4028 */     List<Folder> folders = new ArrayList();
/* 4029 */     for (MailItem item : getItemList(octxt, MailItem.Type.FOLDER, -1, sort)) {
/* 4030 */       folders.add((Folder)item);
/*      */     }
/* 4032 */     return folders;
/*      */   }
/*      */   
/*      */   List<Folder> listAllFolders() {
/* 4036 */     return new ArrayList(this.mFolderCache.values());
/*      */   }
/*      */   
/*      */   public static class FolderNode {
/*      */     public int mId;
/*      */     public String mName;
/*      */     public Folder mFolder;
/* 4043 */     public List<FolderNode> mSubfolders = new ArrayList();
/*      */     
/*      */     public String toString()
/*      */     {
/* 4047 */       return "" + this.mName + " [" + this.mId + "]" + (this.mFolder == null ? " (hidden)" : "");
/*      */     }
/*      */   }
/*      */   
/*      */   public FolderNode getFolderTree(OperationContext octxt, ItemId iid, boolean returnAllVisibleFolders) throws ServiceException
/*      */   {
/* 4053 */     this.lock.lock(false);
/*      */     try
/*      */     {
/* 4056 */       int folderId = iid != null ? iid.getId() : 1;
/* 4057 */       Folder folder = getFolderById(returnAllVisibleFolders ? null : octxt, folderId);
/*      */       
/* 4059 */       Set<Folder> visibleFolders = getVisibleFolders(octxt);
/* 4060 */       return handleFolder(folder, visibleFolders, returnAllVisibleFolders);
/*      */     } finally {
/* 4062 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public FolderNode getFolderTreeByUuid(OperationContext octxt, String uuid, boolean returnAllVisibleFolders) throws ServiceException
/*      */   {
/* 4068 */     this.lock.lock(false);
/*      */     try { Folder folder;
/*      */       Folder folder;
/* 4071 */       if (uuid != null) {
/* 4072 */         folder = getFolderByUuid(returnAllVisibleFolders ? null : octxt, uuid);
/*      */       } else {
/* 4074 */         folder = getFolderById(returnAllVisibleFolders ? null : octxt, 1);
/*      */       }
/*      */       
/* 4077 */       Set<Folder> visibleFolders = getVisibleFolders(octxt);
/* 4078 */       return handleFolder(folder, visibleFolders, returnAllVisibleFolders);
/*      */     } finally {
/* 4080 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   private FolderNode handleFolder(Folder folder, Set<Folder> visible, boolean returnAllVisibleFolders) throws ServiceException
/*      */   {
/* 4086 */     boolean isVisible = (visible == null) || (visible.remove(folder));
/* 4087 */     if ((!isVisible) && (!returnAllVisibleFolders)) {
/* 4088 */       return null;
/*      */     }
/*      */     
/* 4091 */     List<Folder> subfolders = folder.getSubfolders(null);
/* 4092 */     if ((!isVisible) && (subfolders.isEmpty())) {
/* 4093 */       return null;
/*      */     }
/* 4095 */     FolderNode node = new FolderNode();
/* 4096 */     node.mId = folder.getId();
/* 4097 */     node.mName = (node.mId == 11 ? null : folder.getName());
/* 4098 */     node.mFolder = (isVisible ? folder : null);
/*      */     
/*      */ 
/* 4101 */     if ((isVisible) && (visible != null) && (visible.isEmpty())) {
/* 4102 */       return node;
/*      */     }
/*      */     
/* 4105 */     for (Folder subfolder : subfolders) {
/* 4106 */       FolderNode child = handleFolder(subfolder, visible, returnAllVisibleFolders);
/* 4107 */       if (child != null) {
/* 4108 */         node.mSubfolders.add(child);
/* 4109 */         isVisible = true;
/*      */       }
/*      */     }
/*      */     
/* 4113 */     return isVisible ? node : null;
/*      */   }
/*      */   
/*      */   public static boolean isCalendarFolder(Folder f) {
/* 4117 */     MailItem.Type view = f.getDefaultView();
/* 4118 */     return (view == MailItem.Type.APPOINTMENT) || (view == MailItem.Type.TASK);
/*      */   }
/*      */   
/*      */   public List<Mountpoint> getCalendarMountpoints(OperationContext octxt, SortBy sort) throws ServiceException {
/* 4122 */     this.lock.lock();
/*      */     try {
/* 4124 */       List<Mountpoint> calFolders = Lists.newArrayList();
/* 4125 */       for (MailItem item : getItemList(octxt, MailItem.Type.MOUNTPOINT, -1, sort)) {
/* 4126 */         if (isCalendarFolder((Mountpoint)item)) {
/* 4127 */           calFolders.add((Mountpoint)item);
/*      */         }
/*      */       }
/* 4130 */       return calFolders;
/*      */     } finally {
/* 4132 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public List<Folder> getCalendarFolders(OperationContext octxt, SortBy sort) throws ServiceException {
/* 4137 */     this.lock.lock(false);
/*      */     try {
/* 4139 */       List<Folder> calFolders = Lists.newArrayList();
/* 4140 */       for (MailItem item : getItemList(octxt, MailItem.Type.FOLDER, -1, sort)) {
/* 4141 */         if (isCalendarFolder((Folder)item)) {
/* 4142 */           calFolders.add((Folder)item);
/*      */         }
/*      */       }
/* 4145 */       for (MailItem item : getItemList(octxt, MailItem.Type.MOUNTPOINT, -1, sort)) {
/* 4146 */         if (isCalendarFolder((Folder)item)) {
/* 4147 */           calFolders.add((Folder)item);
/*      */         }
/*      */       }
/* 4150 */       return calFolders;
/*      */     } finally {
/* 4152 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public SearchFolder getSearchFolderById(OperationContext octxt, int searchId) throws ServiceException {
/* 4157 */     return (SearchFolder)getItemById(octxt, searchId, MailItem.Type.SEARCHFOLDER);
/*      */   }
/*      */   
/*      */   SearchFolder getSearchFolderById(int searchId) throws ServiceException {
/* 4161 */     return (SearchFolder)getItemById(searchId, MailItem.Type.SEARCHFOLDER);
/*      */   }
/*      */   
/*      */   public Mountpoint getMountpointById(OperationContext octxt, int mptId) throws ServiceException {
/* 4165 */     return (Mountpoint)getItemById(octxt, mptId, MailItem.Type.MOUNTPOINT);
/*      */   }
/*      */   
/*      */   public Mountpoint getMountpointByUuid(OperationContext octxt, String mptUuid) throws ServiceException {
/* 4169 */     return (Mountpoint)getItemByUuid(octxt, mptUuid, MailItem.Type.MOUNTPOINT);
/*      */   }
/*      */   
/*      */   public Note getNoteById(OperationContext octxt, int noteId) throws ServiceException {
/* 4173 */     return (Note)getItemById(octxt, noteId, MailItem.Type.NOTE);
/*      */   }
/*      */   
/*      */   Note getNoteById(int noteId) throws ServiceException {
/* 4177 */     return (Note)getItemById(noteId, MailItem.Type.NOTE);
/*      */   }
/*      */   
/*      */   public List<Note> getNoteList(OperationContext octxt, int folderId) throws ServiceException {
/* 4181 */     return getNoteList(octxt, folderId, SortBy.NONE);
/*      */   }
/*      */   
/*      */   public List<Note> getNoteList(OperationContext octxt, int folderId, SortBy sort) throws ServiceException {
/* 4185 */     List<Note> notes = new ArrayList();
/* 4186 */     for (MailItem item : getItemList(octxt, MailItem.Type.NOTE, folderId, sort)) {
/* 4187 */       notes.add((Note)item);
/*      */     }
/* 4189 */     return notes;
/*      */   }
/*      */   
/*      */   public Chat getChatById(OperationContext octxt, int id) throws ServiceException {
/* 4193 */     return (Chat)getItemById(octxt, id, MailItem.Type.CHAT);
/*      */   }
/*      */   
/*      */   Chat getChatById(int id) throws ServiceException {
/* 4197 */     return (Chat)getItemById(id, MailItem.Type.CHAT);
/*      */   }
/*      */   
/*      */   public List<Chat> getChatList(OperationContext octxt, int folderId) throws ServiceException {
/* 4201 */     return getChatList(octxt, folderId, SortBy.NONE);
/*      */   }
/*      */   
/*      */   public List<Chat> getChatList(OperationContext octxt, int folderId, SortBy sort) throws ServiceException {
/* 4205 */     List<Chat> chats = new ArrayList();
/* 4206 */     for (MailItem item : getItemList(octxt, MailItem.Type.CHAT, folderId, sort)) {
/* 4207 */       chats.add((Chat)item);
/*      */     }
/* 4209 */     return chats;
/*      */   }
/*      */   
/*      */   public Contact getContactById(OperationContext octxt, int id) throws ServiceException {
/* 4213 */     return (Contact)getItemById(octxt, id, MailItem.Type.CONTACT);
/*      */   }
/*      */   
/*      */   Contact getContactById(int id) throws ServiceException {
/* 4217 */     return (Contact)getItemById(id, MailItem.Type.CONTACT);
/*      */   }
/*      */   
/*      */   public List<Contact> getContactList(OperationContext octxt, int folderId) throws ServiceException {
/* 4221 */     return getContactList(octxt, folderId, SortBy.NONE);
/*      */   }
/*      */   
/*      */   public List<Contact> getContactList(OperationContext octxt, int folderId, SortBy sort) throws ServiceException {
/* 4225 */     List<Contact> contacts = new ArrayList();
/* 4226 */     for (MailItem item : getItemList(octxt, MailItem.Type.CONTACT, folderId, sort)) {
/* 4227 */       contacts.add((Contact)item);
/*      */     }
/* 4229 */     return contacts;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public Message getMessageById(OperationContext octxt, int id)
/*      */     throws ServiceException
/*      */   {
/* 4237 */     return (Message)getItemById(octxt, id, MailItem.Type.MESSAGE);
/*      */   }
/*      */   
/*      */   Message getMessageById(int id) throws ServiceException {
/* 4241 */     return (Message)getItemById(id, MailItem.Type.MESSAGE);
/*      */   }
/*      */   
/*      */   Message getMessage(MailItem.UnderlyingData data) throws ServiceException {
/* 4245 */     return (Message)getItem(data);
/*      */   }
/*      */   
/*      */   Message getCachedMessage(Integer id) throws ServiceException {
/* 4249 */     return (Message)getCachedItem(id, MailItem.Type.MESSAGE);
/*      */   }
/*      */   
/*      */   public List<Message> getMessagesByConversation(OperationContext octxt, int convId) throws ServiceException {
/* 4253 */     return getMessagesByConversation(octxt, convId, SortBy.DATE_ASC, -1);
/*      */   }
/*      */   
/*      */   public List<Message> getMessagesByConversation(OperationContext octxt, int convId, SortBy sort, int limit) throws ServiceException
/*      */   {
/* 4258 */     return getMessagesByConversation(octxt, convId, sort, limit, false);
/*      */   }
/*      */   
/*      */   public List<Message> getMessagesByConversation(OperationContext octxt, int convId, SortBy sort, int limit, boolean excludeSpamAndTrash) throws ServiceException
/*      */   {
/* 4263 */     boolean success = false;
/*      */     try {
/* 4265 */       beginReadTransaction("getMessagesByConversation", octxt);
/* 4266 */       List<Message> msgs = getConversationById(convId).getMessages(sort, limit);
/*      */       
/* 4268 */       boolean hasMailboxAccess = hasFullAccess();
/* 4269 */       List<Message> filteredMsgs = new ArrayList(msgs.size());
/* 4270 */       for (Message msg : msgs) {
/* 4271 */         if (((hasMailboxAccess) || (msg.canAccess((short)1))) && (
/*      */         
/*      */ 
/* 4274 */           (!excludeSpamAndTrash) || ((!msg.inTrash()) && (!msg.inSpam()))))
/*      */         {
/*      */ 
/* 4277 */           filteredMsgs.add(msg); }
/*      */       }
/* 4279 */       msgs = filteredMsgs;
/* 4280 */       success = true;
/* 4281 */       return msgs;
/*      */     } finally {
/* 4283 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Conversation getConversationById(OperationContext octxt, int id) throws ServiceException {
/* 4288 */     return (Conversation)getItemById(octxt, id, MailItem.Type.CONVERSATION);
/*      */   }
/*      */   
/*      */   Conversation getConversationById(int id) throws ServiceException {
/* 4292 */     return (Conversation)getItemById(id, MailItem.Type.CONVERSATION);
/*      */   }
/*      */   
/*      */   Conversation getConversation(MailItem.UnderlyingData data) throws ServiceException {
/* 4296 */     return (Conversation)getItem(data);
/*      */   }
/*      */   
/*      */   Conversation getCachedConversation(Integer id) throws ServiceException {
/* 4300 */     return (Conversation)getCachedItem(id, MailItem.Type.CONVERSATION);
/*      */   }
/*      */   
/*      */   public Conversation getConversationByHash(OperationContext octxt, String hash) throws ServiceException {
/* 4304 */     boolean success = false;
/*      */     try {
/* 4306 */       beginReadTransaction("getConversationByHash", octxt);
/* 4307 */       Conversation conv = (Conversation)checkAccess(getConversationByHash(hash));
/* 4308 */       success = true;
/* 4309 */       return conv;
/*      */     } finally {
/* 4311 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   Conversation getConversationByHash(String hash) throws ServiceException {
/* 4316 */     Conversation conv = null;
/*      */     
/* 4318 */     Integer convId = (Integer)this.mConvHashes.get(hash);
/* 4319 */     if (convId != null) {
/* 4320 */       conv = getCachedConversation(convId);
/*      */     }
/* 4322 */     if (conv != null) {
/* 4323 */       return conv;
/*      */     }
/*      */     
/*      */ 
/* 4327 */     MailItem.UnderlyingData data = DbMailItem.getByHash(this, hash);
/* 4328 */     if ((data == null) || (data.type == MailItem.Type.CONVERSATION.toByte())) {
/* 4329 */       return getConversation(data);
/*      */     }
/* 4331 */     return (Conversation)getMessage(data).getParent();
/*      */   }
/*      */   
/*      */   public SenderList getConversationSenderList(int convId) throws ServiceException {
/* 4335 */     boolean success = false;
/*      */     try {
/* 4337 */       beginTransaction("getSenderList", null);
/* 4338 */       Conversation conv = getConversationById(convId);
/* 4339 */       SenderList sl = conv.getSenderList();
/* 4340 */       success = true;
/* 4341 */       return sl;
/*      */     } finally {
/* 4343 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Document getDocumentById(OperationContext octxt, int id) throws ServiceException {
/* 4348 */     return (Document)getItemById(octxt, id, MailItem.Type.DOCUMENT);
/*      */   }
/*      */   
/*      */   public Document getDocumentByUuid(OperationContext octxt, String uuid) throws ServiceException {
/* 4352 */     return (Document)getItemByUuid(octxt, uuid, MailItem.Type.DOCUMENT);
/*      */   }
/*      */   
/*      */   Document getDocumentById(int id) throws ServiceException {
/* 4356 */     return (Document)getItemById(id, MailItem.Type.DOCUMENT);
/*      */   }
/*      */   
/*      */   public List<Document> getDocumentList(OperationContext octxt, int folderId) throws ServiceException {
/* 4360 */     return getDocumentList(octxt, folderId, SortBy.NONE);
/*      */   }
/*      */   
/*      */   public List<Document> getDocumentList(OperationContext octxt, int folderId, SortBy sort) throws ServiceException {
/* 4364 */     this.lock.lock(false);
/*      */     try {
/* 4366 */       List<Document> docs = new ArrayList();
/* 4367 */       for (MailItem item : getItemList(octxt, MailItem.Type.DOCUMENT, folderId, sort)) {
/* 4368 */         docs.add((Document)item);
/*      */       }
/* 4370 */       return docs;
/*      */     } finally {
/* 4372 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public Collection<CalendarItem.CalendarMetadata> getCalendarItemMetadata(int folderId, long start, long end) throws ServiceException
/*      */   {
/* 4378 */     boolean success = false;
/*      */     try {
/* 4380 */       beginReadTransaction("getCalendarItemMetadata", null);
/* 4381 */       Folder f = getFolderById(folderId);
/* 4382 */       if (!f.canAccess((short)1)) {
/* 4383 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */       }
/* 4385 */       success = true;
/* 4386 */       return DbMailItem.getCalendarItemMetadata(f, start, end);
/*      */     } finally {
/* 4388 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private void checkCalendarType(MailItem item) throws ServiceException {
/* 4393 */     MailItem.Type type = item.getType();
/* 4394 */     if ((type != MailItem.Type.APPOINTMENT) && (type != MailItem.Type.TASK)) {
/* 4395 */       throw MailServiceException.NO_SUCH_CALITEM(item.getId());
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public CalendarItem getCalendarItemById(OperationContext octxt, ItemId id)
/*      */     throws ServiceException
/*      */   {
/* 4404 */     if ((id == null) || (!id.belongsTo(this))) {
/* 4405 */       return null;
/*      */     }
/* 4407 */     return getCalendarItemById(octxt, id.getId());
/*      */   }
/*      */   
/*      */   public CalendarItem getCalendarItemById(OperationContext octxt, int id) throws ServiceException {
/* 4411 */     this.lock.lock(false);
/*      */     try {
/* 4413 */       MailItem item = getItemById(octxt, id, MailItem.Type.UNKNOWN);
/* 4414 */       checkCalendarType(item);
/* 4415 */       return (CalendarItem)item;
/*      */     } finally {
/* 4417 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   private CalendarItem getCalendarItemById(int id) throws ServiceException {
/* 4422 */     MailItem item = getItemById(id, MailItem.Type.UNKNOWN);
/* 4423 */     checkCalendarType(item);
/* 4424 */     return (CalendarItem)item;
/*      */   }
/*      */   
/*      */   CalendarItem getCalendarItem(MailItem.UnderlyingData data) throws ServiceException {
/* 4428 */     return (CalendarItem)getItem(data);
/*      */   }
/*      */   
/*      */   public List<MailItem> getCalendarItemList(OperationContext octxt, int folderId) throws ServiceException {
/* 4432 */     return getItemList(octxt, MailItem.Type.UNKNOWN, folderId);
/*      */   }
/*      */   
/*      */   public Appointment getAppointmentById(OperationContext octxt, int id) throws ServiceException {
/* 4436 */     return (Appointment)getItemById(octxt, id, MailItem.Type.APPOINTMENT);
/*      */   }
/*      */   
/*      */   Appointment getAppointmentById(int id) throws ServiceException {
/* 4440 */     return (Appointment)getItemById(id, MailItem.Type.APPOINTMENT);
/*      */   }
/*      */   
/*      */   public List<MailItem> getAppointmentList(OperationContext octxt, int folderId) throws ServiceException {
/* 4444 */     return getItemList(octxt, MailItem.Type.APPOINTMENT, folderId);
/*      */   }
/*      */   
/*      */   public Task getTaskById(OperationContext octxt, int id) throws ServiceException {
/* 4448 */     return (Task)getItemById(octxt, id, MailItem.Type.TASK);
/*      */   }
/*      */   
/*      */   Task getTaskById(int id) throws ServiceException {
/* 4452 */     return (Task)getItemById(id, MailItem.Type.TASK);
/*      */   }
/*      */   
/*      */   public List<MailItem> getTaskList(OperationContext octxt, int folderId) throws ServiceException {
/* 4456 */     return getItemList(octxt, MailItem.Type.TASK, folderId);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public TypedIdList listCalendarItemsForRange(OperationContext octxt, MailItem.Type type, long start, long end, int folderId)
/*      */     throws ServiceException
/*      */   {
/* 4465 */     if (folderId == -1) {
/* 4466 */       return new TypedIdList();
/*      */     }
/* 4468 */     boolean success = false;
/*      */     try {
/* 4470 */       beginReadTransaction("listCalendarItemsForRange", octxt);
/*      */       
/*      */ 
/* 4473 */       getFolderById(folderId);
/*      */       
/*      */ 
/* 4476 */       TypedIdList ids = DbMailItem.listCalendarItems(this, type, start, end, folderId, null);
/* 4477 */       success = true;
/* 4478 */       return ids;
/*      */     } finally {
/* 4480 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<CalendarItem> getCalendarItems(OperationContext octxt, MailItem.Type type, int folderId) throws ServiceException
/*      */   {
/* 4486 */     return getCalendarItemsForRange(octxt, type, -1L, -1L, folderId, null);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public List<CalendarItem> getCalendarItemsForRange(OperationContext octxt, long start, long end, int folderId, int[] excludeFolders)
/*      */     throws ServiceException
/*      */   {
/* 4495 */     return getCalendarItemsForRange(octxt, MailItem.Type.UNKNOWN, start, end, folderId, excludeFolders);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public List<CalendarItem> getCalendarItemsForRange(OperationContext octxt, MailItem.Type type, long start, long end, int folderId, int[] excludeFolders)
/*      */     throws ServiceException
/*      */   {
/* 4526 */     boolean success = false;
/*      */     try {
/* 4528 */       beginReadTransaction("getCalendarItemsForRange", octxt);
/*      */       
/*      */ 
/* 4531 */       if (folderId != -1) {
/* 4532 */         getFolderById(folderId);
/*      */       }
/*      */       
/*      */ 
/* 4536 */       List<CalendarItem> calItems = new ArrayList();
/* 4537 */       List<MailItem.UnderlyingData> invData = DbMailItem.getCalendarItems(this, type, start, end, folderId, excludeFolders);
/*      */       
/* 4539 */       for (MailItem.UnderlyingData data : invData) {
/*      */         try {
/* 4541 */           CalendarItem calItem = getCalendarItem(data);
/* 4542 */           if (((folderId == calItem.getFolderId()) || ((folderId == -1) && (calItem.inMailbox()))) && 
/* 4543 */             (calItem.canAccess((short)1))) {
/* 4544 */             calItems.add(calItem);
/*      */           }
/*      */         }
/*      */         catch (ServiceException e) {
/* 4548 */           ZimbraLog.calendar.warn("Error while retrieving calendar item " + data.id + " in mailbox " + this.mId + "; skipping item", e);
/*      */         }
/*      */       }
/*      */       
/* 4552 */       success = true;
/* 4553 */       return calItems;
/*      */     } finally {
/* 4555 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<Integer> getItemIdList(OperationContext octxt, DbMailItem.QueryParams params) throws ServiceException {
/* 4560 */     boolean success = false;
/*      */     try {
/* 4562 */       beginTransaction("getItemIdList", octxt);
/* 4563 */       List<Integer> msgIds = DbMailItem.getIdsInOrder(this, getOperationConnection(), params, false);
/* 4564 */       success = true;
/* 4565 */       return msgIds;
/*      */     } finally {
/* 4567 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<Pair<Integer, Integer>> getDateAndItemIdList(OperationContext octxt, DbMailItem.QueryParams params) throws ServiceException
/*      */   {
/* 4573 */     boolean success = false;
/*      */     try {
/* 4575 */       beginTransaction("getDateAndItemIdList", octxt);
/* 4576 */       List<Pair<Integer, Integer>> result = DbMailItem.getDatesAndIdsInOrder(this, getOperationConnection(), params, false);
/*      */       
/* 4578 */       success = true;
/* 4579 */       return result;
/*      */     } finally {
/* 4581 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void writeICalendarForCalendarItems(Writer writer, OperationContext octxt, Collection<CalendarItem> calItems, boolean useOutlookCompatMode, boolean ignoreErrors, boolean needAppleICalHacks, boolean trimCalItemsList)
/*      */     throws ServiceException
/*      */   {
/* 4588 */     writeICalendarForCalendarItems(writer, octxt, calItems, null, useOutlookCompatMode, ignoreErrors, needAppleICalHacks, trimCalItemsList, false);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public void writeICalendarForCalendarItems(Writer writer, OperationContext octxt, Collection<CalendarItem> calItems, Folder f, boolean useOutlookCompatMode, boolean ignoreErrors, boolean needAppleICalHacks, boolean trimCalItemsList, boolean escapeHtmlTags)
/*      */     throws ServiceException
/*      */   {
/* 4596 */     writeICalendarForCalendarItems(writer, octxt, calItems, f, useOutlookCompatMode, ignoreErrors, needAppleICalHacks, trimCalItemsList, escapeHtmlTags, false);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public void writeICalendarForCalendarItems(Writer writer, OperationContext octxt, Collection<CalendarItem> calItems, Folder f, boolean useOutlookCompatMode, boolean ignoreErrors, boolean needAppleICalHacks, boolean trimCalItemsList, boolean escapeHtmlTags, boolean includeAttaches)
/*      */     throws ServiceException
/*      */   {
/* 4605 */     this.lock.lock();
/*      */     try {
/* 4607 */       writer.write("BEGIN:VCALENDAR\r\n");
/* 4608 */       if (f != null) {
/* 4609 */         writer.write("X-WR-CALNAME:");
/* 4610 */         writer.write(f.getName());
/* 4611 */         writer.write("\r\n");
/* 4612 */         writer.write("X-WR-CALID:");
/* 4613 */         writer.write(new ItemId(f).toString());
/* 4614 */         writer.write("\r\n");
/*      */       }
/*      */       
/*      */ 
/* 4618 */       ZCalendar.ZProperty prop = new ZCalendar.ZProperty(ZCalendar.ICalTok.PRODID, "Zimbra-Calendar-Provider");
/* 4619 */       prop.toICalendar(writer, needAppleICalHacks);
/* 4620 */       prop = new ZCalendar.ZProperty(ZCalendar.ICalTok.VERSION, "2.0");
/* 4621 */       prop.toICalendar(writer, needAppleICalHacks);
/* 4622 */       prop = new ZCalendar.ZProperty(ZCalendar.ICalTok.METHOD, ZCalendar.ICalTok.PUBLISH.toString());
/* 4623 */       prop.toICalendar(writer, needAppleICalHacks);
/*      */       
/*      */ 
/* 4626 */       ICalTimeZone localTz = Util.getAccountTimeZone(getAccount());
/* 4627 */       TimeZoneMap tzmap = new TimeZoneMap(localTz);
/* 4628 */       for (CalendarItem calItem : calItems) {
/* 4629 */         tzmap.add(calItem.getTimeZoneMap());
/*      */       }
/*      */       
/* 4632 */       for (Iterator<ICalTimeZone> iter = tzmap.tzIterator(); iter.hasNext();) {
/* 4633 */         ICalTimeZone tz = (ICalTimeZone)iter.next();
/* 4634 */         tz.newToVTimeZone().toICalendar(writer, needAppleICalHacks);
/*      */       }
/* 4636 */       tzmap = null;
/*      */       
/*      */ 
/* 4639 */       for (Iterator<CalendarItem> iter = calItems.iterator(); iter.hasNext();) {
/* 4640 */         CalendarItem calItem = (CalendarItem)iter.next();
/* 4641 */         boolean allowPrivateAccess = (calItem.isPublic()) || (calItem.allowPrivateAccess(octxt.getAuthenticatedUser(), octxt.isUsingAdminPrivileges()));
/*      */         
/*      */ 
/* 4644 */         if (trimCalItemsList)
/*      */         {
/* 4646 */           iter.remove();
/*      */         }
/* 4648 */         Invite[] invites = calItem.getInvites();
/* 4649 */         if ((invites != null) && (invites.length > 0)) {
/* 4650 */           boolean appleICalExdateHack = LC.calendar_apple_ical_compatible_canceled_instances.booleanValue();
/* 4651 */           ZCalendar.ZComponent[] comps = null;
/*      */           try {
/* 4653 */             comps = Invite.toVComponents(invites, allowPrivateAccess, useOutlookCompatMode, appleICalExdateHack, includeAttaches);
/*      */           }
/*      */           catch (ServiceException e) {
/* 4656 */             if (ignoreErrors) {
/* 4657 */               ZimbraLog.calendar.warn("Error retrieving iCalendar data for item %s: %s", Integer.valueOf(calItem.getId()), e.getMessage(), e);
/*      */             }
/*      */             else {
/* 4660 */               throw e;
/*      */             }
/*      */           }
/* 4663 */           if (comps != null) {
/* 4664 */             for (ZCalendar.ZComponent comp : comps) {
/* 4665 */               comp.toICalendar(writer, needAppleICalHacks, escapeHtmlTags);
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 4671 */       writer.write("END:VCALENDAR\r\n");
/*      */     } catch (IOException e) {
/* 4673 */       throw ServiceException.FAILURE("Error writing iCalendar", e);
/*      */     } finally {
/* 4675 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public void writeICalendarForRange(Writer writer, OperationContext octxt, long start, long end, int folderId, boolean useOutlookCompatMode, boolean ignoreErrors, boolean needAppleICalHacks) throws ServiceException
/*      */   {
/* 4681 */     writeICalendarForRange(writer, octxt, start, end, folderId, useOutlookCompatMode, ignoreErrors, needAppleICalHacks, false);
/*      */   }
/*      */   
/*      */ 
/*      */   public void writeICalendarForRange(Writer writer, OperationContext octxt, long start, long end, int folderId, boolean useOutlookCompatMode, boolean ignoreErrors, boolean needAppleICalHacks, boolean escapeHtmlTags)
/*      */     throws ServiceException
/*      */   {
/* 4688 */     boolean success = false;
/*      */     try {
/* 4690 */       beginTransaction("writeICalendarForRange", octxt);
/* 4691 */       Collection<CalendarItem> calItems = getCalendarItemsForRange(octxt, start, end, folderId, null);
/* 4692 */       writeICalendarForCalendarItems(writer, octxt, calItems, null, useOutlookCompatMode, ignoreErrors, needAppleICalHacks, true, escapeHtmlTags);
/*      */     }
/*      */     finally {
/* 4695 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public CalSummaryCache.CalendarDataResult getCalendarSummaryForRange(OperationContext octxt, int folderId, MailItem.Type type, long start, long end) throws ServiceException
/*      */   {
/* 4701 */     this.lock.lock(false);
/*      */     try {
/* 4703 */       Folder folder = getFolderById(folderId);
/* 4704 */       if (!folder.canAccess((short)1)) {
/* 4705 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions on folder " + folder.getName());
/*      */       }
/*      */       
/* 4708 */       return CalendarCacheManager.getInstance().getSummaryCache().getCalendarSummary(octxt, getAccountId(), folderId, type, start, end, true);
/*      */     }
/*      */     finally {
/* 4711 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public List<CalSummaryCache.CalendarDataResult> getAllCalendarsSummaryForRange(OperationContext octxt, MailItem.Type type, long start, long end) throws ServiceException
/*      */   {
/* 4717 */     boolean success = false;
/*      */     try
/*      */     {
/* 4720 */       beginReadTransaction("getAllCalendarsSummaryForRange", octxt);
/* 4721 */       success = true;
/* 4722 */       List<CalSummaryCache.CalendarDataResult> list = new ArrayList();
/* 4723 */       for (Folder folder : listAllFolders()) {
/* 4724 */         if ((!folder.inTrash()) && (!folder.inSpam()) && 
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 4730 */           (folder.getDefaultView() == type))
/*      */         {
/*      */           try
/*      */           {
/* 4734 */             if (folder.canAccess((short)1))
/*      */             {
/*      */ 
/* 4737 */               CalSummaryCache.CalendarDataResult result = CalendarCacheManager.getInstance().getSummaryCache().getCalendarSummary(octxt, getAccountId(), folder.getId(), type, start, end, true);
/*      */               
/* 4739 */               if (result != null)
/* 4740 */                 list.add(result);
/*      */             }
/*      */           } catch (ServiceException se) {
/* 4743 */             ZimbraLog.fb.info("Problem getting calendar summary cache for folder '%s' - ignoring", folder.getName(), se);
/*      */             
/* 4745 */             throw se;
/*      */           } }
/*      */       }
/* 4748 */       return list;
/*      */     } finally {
/* 4750 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public String getRewrittenQueryString(OperationContext octxt, SearchParams params)
/*      */     throws ServiceException
/*      */   {
/* 4764 */     if (octxt == null) {
/* 4765 */       throw ServiceException.INVALID_REQUEST("The OperationContext must not be null", null);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 4770 */     ZimbraQuery zq = new ZimbraQuery(octxt, SoapProtocol.Soap12, this, params);
/* 4771 */     return zq.toQueryString();
/*      */   }
/*      */   
/*      */   public FreeBusy getFreeBusy(OperationContext octxt, long start, long end, int folder) throws ServiceException {
/* 4775 */     return getFreeBusy(octxt, getAccount().getName(), start, end, folder, null);
/*      */   }
/*      */   
/*      */   public FreeBusy getFreeBusy(OperationContext octxt, long start, long end, Appointment exAppt) throws ServiceException
/*      */   {
/* 4780 */     return getFreeBusy(octxt, getAccount().getName(), start, end, -1, exAppt);
/*      */   }
/*      */   
/*      */   public FreeBusy getFreeBusy(OperationContext octxt, String name, long start, long end, int folder) throws ServiceException
/*      */   {
/* 4785 */     return getFreeBusy(octxt, name, start, end, folder, null);
/*      */   }
/*      */   
/*      */   public FreeBusy getFreeBusy(OperationContext octxt, String name, long start, long end, int folder, Appointment exAppt) throws ServiceException
/*      */   {
/* 4790 */     this.lock.lock(false);
/*      */     try { boolean asAdmin;
/*      */       Account authAcct;
/*      */       boolean asAdmin;
/* 4794 */       if (octxt != null) {
/* 4795 */         Account authAcct = octxt.getAuthenticatedUser();
/* 4796 */         asAdmin = octxt.isUsingAdminPrivileges();
/*      */       } else {
/* 4798 */         authAcct = null;
/* 4799 */         asAdmin = false;
/*      */       }
/* 4801 */       return LocalFreeBusyProvider.getFreeBusyList(authAcct, asAdmin, this, name, start, end, folder, exAppt);
/*      */     } finally {
/* 4803 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   public static enum BrowseBy {
/* 4808 */     attachments,  domains,  objects;
/*      */     
/*      */ 
/*      */ 
/*      */     private BrowseBy() {}
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public List<BrowseTerm> browse(OperationContext octxt, BrowseBy browseBy, String regex, int max)
/*      */     throws IOException, ServiceException
/*      */   {
/* 4820 */     boolean success = false;
/*      */     try {
/* 4822 */       beginTransaction("browse", octxt);
/* 4823 */       if (!hasFullAccess()) {
/* 4824 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions on this mailbox");
/*      */       }
/* 4826 */       List<BrowseTerm> result = null;
/* 4827 */       Map<String, DomainBrowseTerm> domains; switch (browseBy) {
/*      */       case attachments: 
/* 4829 */         result = this.index.getAttachmentTypes(regex);
/* 4830 */         break;
/*      */       case domains: 
/* 4832 */         domains = new HashMap();
/* 4833 */         for (BrowseTerm term : this.index.getDomains("from", regex)) {
/* 4834 */           DomainBrowseTerm domain = (DomainBrowseTerm)domains.get(term.getText());
/* 4835 */           if (domain == null) {
/* 4836 */             domain = new DomainBrowseTerm(term);
/* 4837 */             domains.put(term.getText(), domain);
/*      */           }
/* 4839 */           domain.addField(DomainBrowseTerm.Field.FROM);
/*      */         }
/* 4841 */         for (BrowseTerm term : this.index.getDomains("to", regex)) {
/* 4842 */           DomainBrowseTerm domain = (DomainBrowseTerm)domains.get(term.getText());
/* 4843 */           if (domain == null) {
/* 4844 */             domain = new DomainBrowseTerm(term);
/* 4845 */             domains.put(term.getText(), domain);
/*      */           }
/* 4847 */           domain.addField(DomainBrowseTerm.Field.TO);
/*      */         }
/* 4849 */         for (BrowseTerm term : this.index.getDomains("cc", regex)) {
/* 4850 */           DomainBrowseTerm domain = (DomainBrowseTerm)domains.get(term.getText());
/* 4851 */           if (domain == null) {
/* 4852 */             domain = new DomainBrowseTerm(term);
/* 4853 */             domains.put(term.getText(), domain);
/*      */           }
/* 4855 */           domain.addField(DomainBrowseTerm.Field.CC);
/*      */         }
/* 4857 */         result = new ArrayList(domains.values());
/* 4858 */         break;
/*      */       case objects: 
/* 4860 */         result = this.index.getObjects(regex);
/* 4861 */         break;
/*      */       default: 
/* 4863 */         if (!$assertionsDisabled) throw new AssertionError(browseBy);
/*      */         break;
/*      */       }
/* 4866 */       Collections.sort(result, new Comparator()
/*      */       {
/*      */         public int compare(BrowseTerm o1, BrowseTerm o2) {
/* 4869 */           int retVal = o2.getFreq() - o1.getFreq();
/* 4870 */           if (retVal == 0) {
/* 4871 */             retVal = o1.getText().compareTo(o2.getText());
/*      */           }
/* 4873 */           return retVal;
/*      */         }
/*      */       });
/*      */       
/* 4877 */       if ((max > 0) && (result.size() > max)) {
/* 4878 */         result = result.subList(0, max);
/*      */       }
/*      */       
/* 4881 */       success = true;
/* 4882 */       return result;
/*      */     } finally {
/* 4884 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void dismissCalendarItemAlarm(OperationContext octxt, int calItemId, long dismissedAt) throws ServiceException
/*      */   {
/* 4890 */     DismissCalendarItemAlarm redoRecorder = new DismissCalendarItemAlarm(getId(), calItemId, dismissedAt);
/* 4891 */     boolean success = false;
/*      */     try {
/* 4893 */       beginTransaction("dismissAlarm", octxt, redoRecorder);
/* 4894 */       CalendarItem calItem = getCalendarItemById(octxt, calItemId);
/* 4895 */       if (calItem == null) {
/* 4896 */         throw MailServiceException.NO_SUCH_CALITEM(calItemId);
/*      */       }
/* 4898 */       markItemModified(calItem, 131072);
/* 4899 */       calItem.snapshotRevision();
/* 4900 */       calItem.updateNextAlarm(dismissedAt + 1L, true);
/* 4901 */       success = true;
/*      */     } finally {
/* 4903 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void snoozeCalendarItemAlarm(OperationContext octxt, int calItemId, long snoozeUntil) throws ServiceException
/*      */   {
/* 4909 */     SnoozeCalendarItemAlarm redoRecorder = new SnoozeCalendarItemAlarm(getId(), calItemId, snoozeUntil);
/* 4910 */     boolean success = false;
/*      */     try {
/* 4912 */       beginTransaction("snoozeAlarm", octxt, redoRecorder);
/* 4913 */       CalendarItem calItem = getCalendarItemById(octxt, calItemId);
/* 4914 */       if (calItem == null) {
/* 4915 */         throw MailServiceException.NO_SUCH_CALITEM(calItemId);
/*      */       }
/* 4917 */       markItemModified(calItem, 131072);
/* 4918 */       calItem.snapshotRevision();
/* 4919 */       calItem.updateNextAlarm(snoozeUntil, false);
/* 4920 */       success = true;
/*      */     } finally {
/* 4922 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class SetCalendarItemData
/*      */   {
/*      */     public Invite invite;
/*      */     public ParsedMessage message;
/*      */     
/*      */     public String toString() {
/* 4932 */       return Objects.toStringHelper(this).add("inv", this.invite).add("hasBody", this.message != null).toString();
/*      */     }
/*      */   }
/*      */   
/*      */   public static final class AddInviteData {
/*      */     public final int calItemId;
/*      */     public final int invId;
/*      */     public final int compNum;
/*      */     public final int modSeq;
/*      */     public final int rev;
/*      */     
/*      */     private AddInviteData(int calItemId, int invId, int compNum, int modSeq, int rev) {
/* 4944 */       this.calItemId = calItemId;
/* 4945 */       this.invId = invId;
/* 4946 */       this.compNum = compNum;
/* 4947 */       this.modSeq = modSeq;
/* 4948 */       this.rev = rev;
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public CalendarItem setCalendarItem(OperationContext octxt, int folderId, int flags, String[] tags, SetCalendarItemData defaultInv, SetCalendarItemData[] exceptions, List<CalendarItem.ReplyInfo> replies, long nextAlarm)
/*      */     throws ServiceException
/*      */   {
/* 4959 */     flags &= (Flag.FLAGS_SYSTEM ^ 0xFFFFFFFF);
/* 4960 */     SetCalendarItem redoRecorder = new SetCalendarItem(getId(), attachmentsIndexingEnabled(), flags, tags);
/*      */     
/* 4962 */     boolean success = false;
/*      */     try {
/* 4964 */       beginTransaction("setCalendarItem", octxt, redoRecorder);
/* 4965 */       Tag.NormalizedTags ntags = new Tag.NormalizedTags(this, tags);
/*      */       
/*      */ 
/* 4968 */       int scidLen = (defaultInv != null ? 1 : 0) + (exceptions != null ? exceptions.length : 0);
/* 4969 */       List<SetCalendarItemData> scidList = new ArrayList(scidLen);
/* 4970 */       if (defaultInv != null) {
/* 4971 */         defaultInv.invite.setLastFullSeqNo(defaultInv.invite.getSeqNo());
/* 4972 */         scidList.add(defaultInv);
/*      */       }
/* 4974 */       if (exceptions != null) {
/* 4975 */         for (SetCalendarItemData scid : exceptions) {
/* 4976 */           scid.invite.setLastFullSeqNo(scid.invite.getSeqNo());
/* 4977 */           scidList.add(scid);
/*      */         }
/*      */       }
/*      */       
/* 4981 */       CalendarItem calItem = null;
/*      */       
/*      */ 
/*      */       Invite currSeries;
/*      */       
/* 4986 */       if (!scidList.isEmpty()) {
/* 4987 */         calItem = getCalendarItemByUid(octxt, ((SetCalendarItemData)scidList.get(0)).invite.getUid());
/* 4988 */         for (SetCalendarItemData scid : scidList) {
/* 4989 */           int idBeingSet = scid.invite.getMailItemId();
/* 4990 */           if (idBeingSet <= 0) {
/* 4991 */             if (calItem != null) {
/* 4992 */               Invite currInv = calItem.getInvite(scid.invite.getRecurId());
/* 4993 */               if (currInv != null) {
/* 4994 */                 scid.invite.setInviteId(currInv.getMailItemId());
/*      */                 
/* 4996 */                 boolean currLO = currInv.isLocalOnly();
/* 4997 */                 boolean newLO = scid.invite.isLocalOnly();
/* 4998 */                 scid.invite.setLocalOnly((currLO) && (newLO));
/*      */               } else {
/* 5000 */                 scid.invite.setInviteId(getNextItemId(-1));
/*      */               }
/*      */             } else {
/* 5003 */               scid.invite.setInviteId(getNextItemId(-1));
/*      */             }
/*      */           }
/*      */         }
/*      */         
/*      */ 
/*      */ 
/* 5010 */         if ((calItem != null) && (calItem.getFolderId() != 3)) {
/* 5011 */           currSeries = calItem.getDefaultInviteOrNull();
/* 5012 */           for (SetCalendarItemData scid : scidList) {
/* 5013 */             if (!scid.invite.hasFreeBusy()) {
/* 5014 */               Invite currInv = calItem.getInvite(scid.invite.getRecurId());
/* 5015 */               if (currInv == null) {
/* 5016 */                 currInv = currSeries;
/*      */               }
/* 5018 */               if ((currInv != null) && (currInv.hasFreeBusy())) {
/* 5019 */                 if (scid.invite.isTransparent())
/*      */                 {
/* 5021 */                   scid.invite.setFreeBusy("F");
/*      */ 
/*      */                 }
/* 5024 */                 else if ("F".equals(currInv.getFreeBusy()))
/*      */                 {
/* 5026 */                   scid.invite.setFreeBusy("B");
/*      */                 }
/*      */                 else
/*      */                 {
/* 5030 */                   scid.invite.setFreeBusy(currInv.getFreeBusy());
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 5040 */       if (!scidList.isEmpty()) {
/* 5041 */         Invite invLog = ((SetCalendarItemData)scidList.get(0)).invite;
/* 5042 */         String idStr = calItem != null ? Integer.toString(calItem.getId()) : "(new)";
/* 5043 */         ZimbraLog.calendar.info("setCalendarItem: id=%s, folderId=%d, subject=\"%s\", UID=%s", new Object[] { idStr, Integer.valueOf(folderId), (invLog != null) && (invLog.isPublic()) ? invLog.getName() : "(private)", invLog.getUid() });
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 5048 */       redoRecorder.setData(defaultInv, exceptions, replies, nextAlarm);
/*      */       
/* 5050 */       CalendarItem.AlarmData oldAlarmData = null;
/* 5051 */       for (SetCalendarItemData scid : scidList) {
/* 5052 */         if (scid.message == null) {
/* 5053 */           scid.invite.setDontIndexMimeMessage(true);
/* 5054 */           String desc = scid.invite.getDescription();
/* 5055 */           if ((desc != null) && (desc.length() > Invite.getMaxDescInMeta())) {
/* 5056 */             MimeMessage mm = CalendarMailSender.createCalendarMessage(scid.invite);
/* 5057 */             scid.message = new ParsedMessage(mm, octxt == null ? System.currentTimeMillis() : octxt.getTimestamp(), true);
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */       SetCalendarItemData scid;
/* 5063 */       if (scidList.size() > 0) {
/* 5064 */         scid = (SetCalendarItemData)scidList.get(0);
/* 5065 */         if (calItem == null)
/*      */         {
/* 5067 */           String method = scid.invite.getMethod();
/* 5068 */           if (("REQUEST".equals(method)) || ("PUBLISH".equals(method))) {
/*      */             try {
/* 5070 */               calItem = createCalendarItem(folderId, flags, ntags, scid.invite.getUid(), scid.message, scid.invite, null);
/*      */             } catch (MailServiceException e) {
/* 5072 */               if (e.getCode() == "mail.ALREADY_EXISTS")
/*      */               {
/* 5074 */                 ZimbraLog.calendar.error("failed to create calendar item; already exists. cause: " + (scidList.isEmpty() ? "no items in uid list." : new StringBuilder().append("uid not found in appointment: ").append(((SetCalendarItemData)scidList.get(0)).invite.getUid()).append(" or bad mail_item type").toString()));
/*      */               }
/*      */               
/*      */ 
/*      */ 
/* 5079 */               throw e;
/*      */             }
/*      */           } else {
/* 5082 */             return null;
/*      */           }
/*      */         } else {
/* 5085 */           calItem.snapshotRevision();
/*      */           
/*      */ 
/* 5088 */           if (calItem.getAlarmData() != null) {
/* 5089 */             oldAlarmData = (CalendarItem.AlarmData)calItem.getAlarmData().clone();
/*      */           }
/*      */           
/* 5092 */           calItem.setTags(flags, ntags);
/* 5093 */           calItem.processNewInvite(scid.message, scid.invite, folderId, nextAlarm, false, true);
/*      */         }
/* 5095 */         redoRecorder.setCalendarItemAttrs(calItem.getId(), calItem.getFolderId());
/*      */       }
/* 5097 */       if (scidList.size() > 1)
/*      */       {
/* 5099 */         scidList.remove(0);
/*      */         
/* 5101 */         calItem.processNewInviteExceptions(scidList, folderId, nextAlarm, false, false);
/*      */       }
/*      */       
/*      */ 
/* 5105 */       if (nextAlarm == 0L) {
/* 5106 */         nextAlarm = oldAlarmData != null ? oldAlarmData.getNextAt() : -2L;
/*      */       }
/* 5108 */       calItem.updateNextAlarm(nextAlarm, oldAlarmData, false);
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 5113 */       if (replies != null) {
/* 5114 */         calItem.setReplies(replies);
/*      */       }
/* 5116 */       this.index.add(calItem);
/*      */       
/* 5118 */       success = true;
/* 5119 */       return calItem;
/*      */     } finally {
/* 5121 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public int fixAllCalendarItemTZ(OperationContext octxt, long after, TimeZoneFixupRules fixupRules)
/*      */     throws ServiceException
/*      */   {
/* 5132 */     int numFixedCalItems = 0;
/* 5133 */     int numFixedTZs = 0;
/* 5134 */     ZimbraLog.calendar.info("Started: timezone fixup in calendar of mailbox " + getId());
/* 5135 */     List<List<MailItem>> lists = new ArrayList(2);
/* 5136 */     lists.add(getItemList(octxt, MailItem.Type.APPOINTMENT));
/* 5137 */     lists.add(getItemList(octxt, MailItem.Type.TASK));
/* 5138 */     for (List<MailItem> items : lists)
/* 5139 */       for (iter = items.iterator(); iter.hasNext();) {
/* 5140 */         Object obj = iter.next();
/* 5141 */         if ((obj instanceof CalendarItem))
/*      */         {
/*      */ 
/* 5144 */           CalendarItem calItem = (CalendarItem)obj;
/* 5145 */           long end = calItem.getEndTime();
/* 5146 */           if (end > after)
/*      */           {
/*      */             try
/*      */             {
/* 5150 */               int num = fixCalendarItemTZ(octxt, calItem.getId(), fixupRules);
/* 5151 */               numFixedTZs += num;
/* 5152 */               if (num > 0) {
/* 5153 */                 numFixedCalItems++;
/*      */               }
/*      */             } catch (ServiceException e) {
/* 5156 */               ZimbraLog.calendar.error("Error fixing calendar item " + calItem.getId() + " in mailbox " + getId() + ": " + e.getMessage(), e);
/*      */             } }
/*      */         }
/*      */       }
/*      */     Iterator<MailItem> iter;
/* 5161 */     ZimbraLog.calendar.info("Finished: timezone fixup in calendar of mailbox " + getId() + "; fixed " + numFixedTZs + " timezone entries in " + numFixedCalItems + " calendar items");
/*      */     
/* 5163 */     return numFixedCalItems;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public int fixCalendarItemTZ(OperationContext octxt, int calItemId, TimeZoneFixupRules fixupRules)
/*      */     throws ServiceException
/*      */   {
/* 5175 */     FixCalendarItemTZ redoRecorder = new FixCalendarItemTZ(getId(), calItemId);
/* 5176 */     boolean success = false;
/*      */     try {
/* 5178 */       beginTransaction("fixCalendarItemTimeZone2", octxt, redoRecorder);
/* 5179 */       CalendarItem calItem = getCalendarItemById(octxt, calItemId);
/* 5180 */       Map<String, ICalTimeZone> replaced = new HashMap();
/* 5181 */       int numFixed = fixupRules.fixCalendarItem(calItem, replaced);
/* 5182 */       CalendarItem.Callback cb; if (numFixed > 0) {
/* 5183 */         ZimbraLog.calendar.info("Fixed " + numFixed + " timezone entries in calendar item " + calItem.getId());
/* 5184 */         redoRecorder.setReplacementMap(replaced);
/* 5185 */         markItemModified(calItem, 196608);
/* 5186 */         calItem.snapshotRevision();
/* 5187 */         calItem.saveMetadata();
/*      */         
/*      */ 
/*      */ 
/*      */ 
/* 5192 */         uncacheItem(Integer.valueOf(calItemId));
/* 5193 */         calItem = getCalendarItemById(octxt, calItemId);
/* 5194 */         success = true;
/*      */         
/* 5196 */         cb = CalendarItem.getCallback();
/* 5197 */         if (cb != null) {
/* 5198 */           cb.modified(calItem);
/*      */         }
/*      */       }
/* 5201 */       return numFixed;
/*      */     } finally {
/* 5203 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public int fixAllCalendarItemEndTime(OperationContext octxt) throws ServiceException {
/* 5208 */     int numFixed = 0;
/* 5209 */     ZimbraLog.calendar.info("Started: end time fixup in calendar of mailbox " + getId());
/*      */     
/* 5211 */     List<MailItem>[] lists = new List[2];
/* 5212 */     lists[0] = getItemList(octxt, MailItem.Type.APPOINTMENT);
/* 5213 */     lists[1] = getItemList(octxt, MailItem.Type.TASK);
/* 5214 */     Iterator<MailItem> iter; for (List<MailItem> items : lists) {
/* 5215 */       for (iter = items.iterator(); iter.hasNext();) {
/* 5216 */         Object obj = iter.next();
/* 5217 */         if ((obj instanceof CalendarItem))
/*      */         {
/*      */ 
/* 5220 */           CalendarItem calItem = (CalendarItem)obj;
/*      */           try {
/* 5222 */             numFixed += fixCalendarItemEndTime(octxt, calItem);
/*      */           } catch (ServiceException e) {
/* 5224 */             ZimbraLog.calendar.error("Error fixing calendar item " + calItem.getId() + " in mailbox " + getId() + ": " + e.getMessage(), e);
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 5230 */     ZimbraLog.calendar.info("Finished: end time fixup in calendar of mailbox " + getId() + "; fixed " + numFixed + " entries");
/*      */     
/*      */ 
/* 5233 */     return numFixed;
/*      */   }
/*      */   
/*      */   public int fixCalendarItemEndTime(OperationContext octxt, CalendarItem calItem) throws ServiceException {
/* 5237 */     FixCalendarItemEndTime redoRecorder = new FixCalendarItemEndTime(getId(), calItem.getId());
/* 5238 */     boolean success = false;
/*      */     try {
/* 5240 */       beginTransaction("fixupCalendarItemEndTime", octxt, redoRecorder);
/* 5241 */       int numFixed = calItem.fixRecurrenceEndTime();
/* 5242 */       if (numFixed > 0) {
/* 5243 */         ZimbraLog.calendar.info("Fixed calendar item " + calItem.getId());
/* 5244 */         calItem.snapshotRevision();
/* 5245 */         calItem.saveMetadata();
/* 5246 */         success = true;
/*      */       }
/* 5248 */       return numFixed;
/*      */     } finally {
/* 5250 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public int fixAllCalendarItemPriority(OperationContext octxt) throws ServiceException {
/* 5255 */     int numFixed = 0;
/* 5256 */     ZimbraLog.calendar.info("Started: priority fixup in calendar of mailbox " + getId());
/*      */     
/* 5258 */     List<MailItem>[] lists = new List[2];
/* 5259 */     lists[0] = getItemList(octxt, MailItem.Type.APPOINTMENT);
/* 5260 */     lists[1] = getItemList(octxt, MailItem.Type.TASK);
/* 5261 */     Iterator<MailItem> iter; for (List<MailItem> items : lists) {
/* 5262 */       for (iter = items.iterator(); iter.hasNext();) {
/* 5263 */         Object obj = iter.next();
/* 5264 */         if ((obj instanceof CalendarItem))
/*      */         {
/*      */ 
/* 5267 */           CalendarItem calItem = (CalendarItem)obj;
/*      */           try {
/* 5269 */             numFixed += fixCalendarItemPriority(octxt, calItem);
/*      */           } catch (ServiceException e) {
/* 5271 */             ZimbraLog.calendar.error("Error fixing calendar item " + calItem.getId() + " in mailbox " + getId() + ": " + e.getMessage(), e);
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 5277 */     ZimbraLog.calendar.info("Finished: priority fixup in calendar of mailbox " + getId() + "; fixed " + numFixed + " entries");
/*      */     
/*      */ 
/* 5280 */     return numFixed;
/*      */   }
/*      */   
/*      */   public int fixCalendarItemPriority(OperationContext octxt, CalendarItem calItem) throws ServiceException {
/* 5284 */     FixCalendarItemPriority redoRecorder = new FixCalendarItemPriority(getId(), calItem.getId());
/* 5285 */     boolean success = false;
/*      */     try {
/* 5287 */       beginTransaction("fixupCalendarItemPriority", octxt, redoRecorder);
/* 5288 */       int flags = calItem.mData.getFlags() & ((Flag.BITMASK_HIGH_PRIORITY | Flag.BITMASK_LOW_PRIORITY) ^ 0xFFFFFFFF);
/* 5289 */       Invite[] invs = calItem.getInvites();
/* 5290 */       if (invs != null) {
/* 5291 */         for (Invite cur : invs) {
/* 5292 */           String method = cur.getMethod();
/* 5293 */           if ((method.equals(ZCalendar.ICalTok.REQUEST.toString())) || (method.equals(ZCalendar.ICalTok.PUBLISH.toString())))
/*      */           {
/* 5295 */             if (cur.isHighPriority()) {
/* 5296 */               flags |= Flag.BITMASK_HIGH_PRIORITY;
/*      */             }
/* 5298 */             if (cur.isLowPriority()) {
/* 5299 */               flags |= Flag.BITMASK_LOW_PRIORITY;
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/* 5304 */       int numFixed = 0;
/* 5305 */       if (flags != calItem.mData.getFlags()) {
/* 5306 */         ZimbraLog.calendar.info("Fixed calendar item " + calItem.getId());
/* 5307 */         markItemModified(calItem, 131072);
/* 5308 */         calItem.mData.setFlags(flags);
/* 5309 */         calItem.snapshotRevision();
/* 5310 */         calItem.saveMetadata();
/* 5311 */         success = true;
/* 5312 */         numFixed = 1;
/*      */       }
/* 5314 */       return numFixed;
/*      */     } finally {
/* 5316 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public AddInviteData addInvite(OperationContext octxt, Invite inv, int folderId) throws ServiceException
/*      */   {
/* 5322 */     boolean addRevision = true;
/* 5323 */     return addInvite(octxt, inv, folderId, null, false, false, addRevision);
/*      */   }
/*      */   
/*      */   public AddInviteData addInvite(OperationContext octxt, Invite inv, int folderId, ParsedMessage pm) throws ServiceException
/*      */   {
/* 5328 */     boolean addRevision = true;
/* 5329 */     return addInvite(octxt, inv, folderId, pm, false, false, addRevision);
/*      */   }
/*      */   
/*      */   public AddInviteData addInvite(OperationContext octxt, Invite inv, int folderId, boolean preserveExistingAlarms, boolean addRevision) throws ServiceException
/*      */   {
/* 5334 */     return addInvite(octxt, inv, folderId, null, preserveExistingAlarms, false, addRevision);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public AddInviteData addInvite(OperationContext octxt, Invite inv, int folderId, ParsedMessage pm, boolean preserveExistingAlarms, boolean discardExistingInvites, boolean addRevision)
/*      */     throws ServiceException
/*      */   {
/* 5355 */     if (pm == null) {
/* 5356 */       inv.setDontIndexMimeMessage(true);
/* 5357 */       String desc = inv.getDescription();
/* 5358 */       if ((inv.hasAttachment()) || ((desc != null) && (desc.length() > Invite.getMaxDescInMeta()))) {
/* 5359 */         MimeMessage mm = CalendarMailSender.createCalendarMessage(inv);
/* 5360 */         pm = new ParsedMessage(mm, octxt == null ? System.currentTimeMillis() : octxt.getTimestamp(), true);
/*      */       }
/*      */     }
/*      */     
/* 5364 */     byte[] data = null;
/*      */     try {
/* 5366 */       if (pm != null) {
/* 5367 */         data = pm.getRawData();
/*      */       }
/*      */     } catch (IOException ioe) {
/* 5370 */       throw ServiceException.FAILURE("Caught IOException", ioe);
/*      */     }
/*      */     
/* 5373 */     CreateInvite redoRecorder = new CreateInvite(this.mId, inv, folderId, data, preserveExistingAlarms, discardExistingInvites, addRevision);
/*      */     
/*      */ 
/* 5376 */     boolean success = false;
/*      */     try {
/* 5378 */       beginTransaction("addInvite", octxt, redoRecorder);
/* 5379 */       CreateInvite redoPlayer = octxt == null ? null : (CreateInvite)octxt.getPlayer();
/*      */       
/* 5381 */       if ((redoPlayer == null) || (redoPlayer.getCalendarItemId() == 0)) {
/* 5382 */         int currId = inv.getMailItemId();
/* 5383 */         if (currId <= 0) {
/* 5384 */           inv.setInviteId(getNextItemId(-1));
/*      */         } else {
/* 5386 */           inv.setInviteId(currId);
/*      */         }
/*      */       }
/*      */       
/* 5390 */       CalendarItem calItem = getCalendarItemByUid(octxt, inv.getUid());
/* 5391 */       boolean processed = true;
/* 5392 */       Object currInv; if (calItem == null)
/*      */       {
/* 5394 */         if ((inv.getMethod().equals("REQUEST")) || (inv.getMethod().equals("PUBLISH"))) {
/* 5395 */           calItem = createCalendarItem(folderId, 0, null, inv.getUid(), pm, inv, null);
/*      */         } else {
/* 5397 */           return null;
/*      */         }
/*      */       } else {
/* 5400 */         if (!checkItemChangeID(calItem)) {
/* 5401 */           throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */         }
/* 5403 */         if ((inv.getMethod().equals("REQUEST")) || (inv.getMethod().equals("PUBLISH")))
/*      */         {
/* 5405 */           currInv = calItem.getInvite(inv.getRecurId());
/* 5406 */           if (currInv != null) {
/* 5407 */             inv.setInviteId(((Invite)currInv).getMailItemId());
/*      */           }
/*      */         }
/* 5410 */         if (addRevision) {
/* 5411 */           calItem.snapshotRevision();
/*      */         }
/* 5413 */         processed = calItem.processNewInvite(pm, inv, folderId, 0L, preserveExistingAlarms, discardExistingInvites);
/*      */       }
/*      */       
/*      */ 
/* 5417 */       if (Invite.isOrganizerMethod(inv.getMethod())) {
/* 5418 */         this.index.add(calItem);
/*      */       }
/*      */       
/* 5421 */       redoRecorder.setCalendarItemAttrs(calItem.getId(), calItem.getFolderId());
/*      */       
/* 5423 */       success = true;
/* 5424 */       if (processed) {
/* 5425 */         return new AddInviteData(calItem.getId(), inv.getMailItemId(), inv.getComponentNum(), calItem.getModifiedSequence(), calItem.getSavedSequence(), null);
/*      */       }
/*      */       
/* 5428 */       return null;
/*      */     }
/*      */     finally {
/* 5431 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public CalendarItem getCalendarItemByUid(OperationContext octxt, String uid) throws ServiceException {
/* 5436 */     boolean success = false;
/*      */     try {
/* 5438 */       beginReadTransaction("getCalendarItemByUid", octxt);
/* 5439 */       MailItem.UnderlyingData data = DbMailItem.getCalendarItem(this, uid);
/* 5440 */       CalendarItem calItem = (CalendarItem)getItem(data);
/* 5441 */       success = true;
/* 5442 */       return calItem;
/*      */     } finally {
/* 5444 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Map<String, CalendarItem> getCalendarItemsByUid(OperationContext octxt, List<String> uids) throws ServiceException
/*      */   {
/* 5450 */     boolean success = false;
/*      */     try {
/* 5452 */       beginTransaction("getCalendarItemsByUid", octxt);
/* 5453 */       ArrayList<String> uidList = new ArrayList(uids);
/* 5454 */       Map<String, CalendarItem> calItems = new HashMap();
/* 5455 */       List<MailItem.UnderlyingData> invData = DbMailItem.getCalendarItems(this, uids);
/* 5456 */       for (MailItem.UnderlyingData data : invData) {
/*      */         try {
/* 5458 */           CalendarItem calItem = getCalendarItem(data);
/* 5459 */           calItems.put(calItem.getUid(), calItem);
/* 5460 */           uidList.remove(calItem.getUid());
/*      */         } catch (ServiceException e) {
/* 5462 */           ZimbraLog.calendar.warn("Error while retrieving calendar item %d; skipping item", Integer.valueOf(data.id), e);
/*      */         }
/*      */       }
/* 5465 */       success = true;
/* 5466 */       for (String missingUid : uidList) {
/* 5467 */         calItems.put(missingUid, null);
/*      */       }
/* 5469 */       return calItems;
/*      */     } finally {
/* 5471 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public boolean dedupeForSelfMsg(ParsedMessage pm) throws ServiceException
/*      */   {
/* 5477 */     if (pm == null) {
/* 5478 */       return false;
/*      */     }
/* 5480 */     ParsedMessage.CalendarPartInfo cpi = pm.getCalendarPartInfo();
/* 5481 */     String msgidHeader = pm.getMessageID();
/* 5482 */     boolean dedupe = false;
/*      */     
/* 5484 */     if (msgidHeader == null) {
/* 5485 */       return false;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 5490 */     if ((this.mSentMessageIDs.containsKey(msgidHeader)) && ((cpi == null) || (!CalendarItem.isAcceptableInvite(getAccount(), cpi))))
/*      */     {
/* 5492 */       Account acct = getAccount();
/* 5493 */       switch (acct.getPrefDedupeMessagesSentToSelf()) {
/*      */       case dedupeAll: 
/* 5495 */         dedupe = true;
/* 5496 */         break;
/*      */       case secondCopyifOnToOrCC: 
/*      */         try
/*      */         {
/* 5500 */           dedupe = !AccountUtil.isDirectRecipient(acct, pm.getMimeMessage());
/*      */         } catch (Exception e) {
/* 5502 */           ZimbraLog.mailbox.info(e.getMessage());
/*      */         }
/*      */       }
/*      */       
/*      */     }
/*      */     
/*      */ 
/* 5509 */     return dedupe;
/*      */   }
/*      */   
/*      */   public int getConversationIdFromReferent(MimeMessage newMsg, int parentID)
/*      */   {
/*      */     try {
/* 5515 */       Message parentMsg = getMessageById(null, parentID);
/* 5516 */       if (parentMsg.getNormalizedSubject().equals(ParsedMessage.normalize(Mime.getSubject(newMsg)))) {
/* 5517 */         return parentMsg.getConversationId();
/*      */       }
/*      */     } catch (Exception e) {
/* 5520 */       if (!(e instanceof MailServiceException.NoSuchItemException)) {
/* 5521 */         ZimbraLog.mailbox.warn("ignoring error while checking conversation: %d", Integer.valueOf(parentID), e);
/*      */       }
/*      */     }
/* 5524 */     return -1;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public void processICalReply(OperationContext octxt, Invite inv, String sender)
/*      */     throws ServiceException
/*      */   {
/* 5533 */     ICalReply redoRecorder = new ICalReply(getId(), inv, sender);
/* 5534 */     boolean success = false;
/*      */     try {
/* 5536 */       beginTransaction("iCalReply", octxt, redoRecorder);
/* 5537 */       String uid = inv.getUid();
/* 5538 */       CalendarItem calItem = getCalendarItemByUid(octxt, uid);
/* 5539 */       if (calItem == null) {
/* 5540 */         ZimbraLog.calendar.warn("Unknown calendar item UID %s", new Object[] { uid });
/*      */       }
/*      */       else {
/* 5543 */         calItem.snapshotRevision();
/* 5544 */         calItem.processNewInviteReply(inv, sender);
/* 5545 */         success = true;
/*      */       }
/* 5547 */     } finally { endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private AuthToken getAuthToken(OperationContext octxt) throws ServiceException {
/* 5552 */     AuthToken authToken = octxt == null ? null : octxt.getAuthToken();
/*      */     
/* 5554 */     if (authToken == null) {
/* 5555 */       Account authuser = octxt == null ? getAccount() : octxt.getAuthenticatedUser();
/* 5556 */       boolean isAdminRequest = octxt == null ? false : octxt.isUsingAdminPrivileges();
/* 5557 */       authToken = AuthProvider.getAuthToken(authuser, isAdminRequest);
/*      */     }
/* 5559 */     return authToken;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void processICalReplies(OperationContext octxt, ZCalendar.ZVCalendar cal, String sender)
/*      */     throws ServiceException
/*      */   {
/* 5572 */     String prodId = cal.getPropVal(ZCalendar.ICalTok.PRODID, null);
/* 5573 */     boolean fromOutlook = (prodId != null) && (prodId.toLowerCase().contains("microsoft"));
/*      */     
/* 5575 */     AccountUtil.AccountAddressMatcher acctMatcher = new AccountUtil.AccountAddressMatcher(getAccount());
/* 5576 */     List<Invite> components = Invite.createFromCalendar(getAccount(), null, cal, false);
/* 5577 */     for (Invite inv : components) { String orgAddress;
/*      */       String orgAddress;
/* 5579 */       if (inv.hasOrganizer()) {
/* 5580 */         ZOrganizer org = inv.getOrganizer();
/* 5581 */         orgAddress = org.getAddress();
/*      */       } else {
/* 5583 */         ZimbraLog.calendar.warn("No ORGANIZER found in REPLY.  Assuming current mailbox.");
/* 5584 */         orgAddress = getAccount().getName();
/*      */       }
/* 5586 */       if (acctMatcher.matches(orgAddress))
/*      */       {
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 5592 */         if ((fromOutlook) && (!inv.isAllDayEvent()) && (inv.hasRecurId())) {
/* 5593 */           RecurId rid = inv.getRecurId();
/* 5594 */           if ((rid.getDt() != null) && (rid.getDt().hasZeroTime())) {
/* 5595 */             CalendarItem calItem = getCalendarItemByUid(octxt, inv.getUid());
/* 5596 */             if (calItem != null) {
/* 5597 */               Invite seriesInv = calItem.getDefaultInviteOrNull();
/* 5598 */               if (seriesInv != null) {
/* 5599 */                 ParsedDateTime seriesDtStart = seriesInv.getStartTime();
/* 5600 */                 if (seriesDtStart != null) {
/* 5601 */                   ParsedDateTime fixedDt = seriesDtStart.cloneWithNewDate(rid.getDt());
/* 5602 */                   RecurId fixedRid = new RecurId(fixedDt, rid.getRange());
/* 5603 */                   ZimbraLog.calendar.debug("Fixed up invalid RECURRENCE-ID with zero time; before=[%s], after=[%s]", new Object[] { rid, fixedRid });
/*      */                   
/* 5605 */                   inv.setRecurId(fixedRid);
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/* 5611 */         processICalReply(octxt, inv, sender);
/*      */       } else {
/* 5613 */         Account orgAccount = inv.getOrganizerAccount();
/*      */         
/* 5615 */         if (orgAccount == null) {
/* 5616 */           ZimbraLog.calendar.warn("Unknown organizer " + orgAddress + " in REPLY");
/*      */ 
/*      */         }
/* 5619 */         else if (Provisioning.onLocalServer(orgAccount))
/*      */         {
/* 5621 */           Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(orgAccount);
/* 5622 */           OperationContext orgOctxt = new OperationContext(mbox);
/* 5623 */           mbox.processICalReply(orgOctxt, inv, sender);
/*      */         }
/*      */         else {
/* 5626 */           String uri = AccountUtil.getSoapUri(orgAccount);
/* 5627 */           if (uri == null) {
/* 5628 */             ZimbraLog.calendar.warn("Unable to determine URI for organizer account %s", new Object[] { orgAddress });
/*      */           }
/*      */           else
/*      */           {
/*      */             try
/*      */             {
/*      */ 
/* 5635 */               StringWriter sr = null;
/*      */               String ical;
/* 5637 */               try { sr = new StringWriter();
/* 5638 */                 inv.setMethod(ZCalendar.ICalTok.REPLY.toString());
/* 5639 */                 inv.newToICalendar(true).toICalendar(sr);
/* 5640 */                 ical = sr.toString();
/*      */               } finally {
/* 5642 */                 if (sr != null) {
/* 5643 */                   sr.close();
/*      */                 }
/*      */               }
/* 5646 */               ZMailbox.Options options = new ZMailbox.Options();
/* 5647 */               AuthToken authToken = AuthToken.getCsrfUnsecuredAuthToken(getAuthToken(octxt));
/* 5648 */               options.setAuthToken(authToken.toZAuthToken());
/* 5649 */               options.setTargetAccount(orgAccount.getName());
/* 5650 */               options.setTargetAccountBy(Key.AccountBy.name);
/* 5651 */               options.setUri(uri);
/* 5652 */               options.setNoSession(true);
/* 5653 */               ZMailbox zmbox = ZMailbox.getMailbox(options);
/* 5654 */               zmbox.iCalReply(ical, sender);
/*      */             } catch (IOException e) {
/* 5656 */               throw ServiceException.FAILURE("Error while posting REPLY to organizer mailbox host", e);
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   public CalendarItemInfo getRemoteCalItemByUID(Account ownerAccount, String uid, boolean includeInvites, boolean includeContent) throws ServiceException
/*      */   {
/* 5666 */     ZMailbox.Options options = new ZMailbox.Options();
/* 5667 */     AuthToken authToken = AuthToken.getCsrfUnsecuredAuthToken(getAuthToken(getOperationContext()));
/* 5668 */     options.setAuthToken(authToken.toZAuthToken());
/* 5669 */     options.setTargetAccount(getAccount().getName());
/* 5670 */     options.setTargetAccountBy(Key.AccountBy.name);
/* 5671 */     options.setUri(AccountUtil.getSoapUri(ownerAccount));
/* 5672 */     options.setNoSession(true);
/* 5673 */     ZMailbox zmbox = ZMailbox.getMailbox(options);
/*      */     try {
/* 5675 */       return zmbox.getRemoteCalItemByUID(ownerAccount.getId(), uid, includeInvites, includeContent);
/*      */     } catch (ServiceException e) {
/* 5677 */       String exceptionCode = e.getCode();
/* 5678 */       if ((exceptionCode.equals("account.NO_SUCH_ACCOUNT")) || (exceptionCode.equals("mail.NO_SUCH_CALITEM")))
/*      */       {
/* 5680 */         ZimbraLog.calendar.debug("Either remote acct or calendar item not found [%s]", new Object[] { exceptionCode });
/*      */       } else
/* 5682 */         ZimbraLog.calendar.debug("Unexpected exception thrown when getting remote calendar item - ignoring", e);
/*      */     }
/* 5684 */     return null;
/*      */   }
/*      */   
/*      */   public Message addMessage(OperationContext octxt, InputStream in, long sizeHint, Long receivedDate, DeliveryOptions dopt, DeliveryContext dctxt, ItemData id)
/*      */     throws IOException, ServiceException
/*      */   {
/* 5690 */     int bufLen = Provisioning.getInstance().getLocalServer().getMailDiskStreamingThreshold();
/* 5691 */     CopyInputStream cs = new CopyInputStream(in, sizeHint, bufLen, bufLen);
/* 5692 */     in = cs;
/* 5693 */     Blob blob = null;
/*      */     try
/*      */     {
/* 5696 */       BufferStream bs = cs.getBufferStream();
/* 5697 */       ParsedMessage pm = null;
/*      */       
/* 5699 */       Rfc822ValidationInputStream validator = null;
/* 5700 */       if (LC.zimbra_lmtp_validate_messages.booleanValue()) {
/* 5701 */         validator = new Rfc822ValidationInputStream(cs, LC.zimbra_lmtp_max_line_length.longValue());
/* 5702 */         in = validator;
/*      */       }
/*      */       
/* 5705 */       blob = StoreManager.getInstance().storeIncoming(in);
/*      */       
/* 5707 */       if ((id != null) && (id.ud != null) && (id.ud.getBlobDigest() != null) && (!id.ud.getBlobDigest().isEmpty())) {
/* 5708 */         blob.setDigest(id.ud.getBlobDigest());
/*      */       }
/*      */       
/* 5711 */       if ((validator != null) && (!validator.isValid())) {
/* 5712 */         StoreManager.getInstance().delete(blob);
/* 5713 */         throw ServiceException.INVALID_REQUEST("Message content is invalid.", null);
/*      */       }
/*      */       
/* 5716 */       pm = new ParsedMessage(new ParsedMessageOptions(blob, bs.isPartial() ? null : bs.getBuffer(), receivedDate, Boolean.valueOf(attachmentsIndexingEnabled())));
/* 5717 */       cs.release();
/* 5718 */       if (dctxt == null) {
/* 5719 */         dctxt = new DeliveryContext();
/*      */       }
/* 5721 */       dctxt.setIncomingBlob(blob);
/* 5722 */       return addMessage(octxt, pm, dopt, dctxt);
/*      */     } finally {
/* 5724 */       cs.release();
/* 5725 */       StoreManager.getInstance().quietDelete(blob);
/*      */     }
/*      */   }
/*      */   
/*      */   public Message addMessage(OperationContext octxt, InputStream in, long sizeHint, Long receivedDate, DeliveryOptions dopt, DeliveryContext dctxt) throws IOException, ServiceException
/*      */   {
/* 5731 */     return addMessage(octxt, in, sizeHint, receivedDate, dopt, dctxt, null);
/*      */   }
/*      */   
/*      */   public Message addMessage(OperationContext octxt, ParsedMessage pm, DeliveryOptions dopt, DeliveryContext dctxt) throws IOException, ServiceException
/*      */   {
/* 5736 */     return addMessage(octxt, pm, dopt, dctxt, null);
/*      */   }
/*      */   
/*      */   public Message addMessage(OperationContext octxt, ParsedMessage pm, DeliveryOptions dopt, DeliveryContext dctxt, Message.DraftInfo dinfo) throws IOException, ServiceException
/*      */   {
/* 5741 */     return addMessage(octxt, pm, dopt.getFolderId(), dopt.getNoICal(), dopt.getFlags(), dopt.getTags(), dopt.getConversationId(), dopt.getRecipientEmail(), dinfo, dopt.getCustomMetadata(), dctxt);
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   private Message addMessage(OperationContext octxt, ParsedMessage pm, int folderId, boolean noICal, int flags, String[] tags, int conversationId, String rcptEmail, Message.DraftInfo dinfo, MailItem.CustomMetadata customData, DeliveryContext dctxt)
/*      */     throws IOException, ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: getstatic 1170	com/zimbra/cs/stats/ZimbraPerf:STOPWATCH_MBOX_ADD_MSG	Lcom/zimbra/common/stats/StopWatch;
/*      */     //   3: invokevirtual 1171	com/zimbra/common/stats/StopWatch:start	()J
/*      */     //   6: lstore 12
/*      */     //   8: iload 4
/*      */     //   10: ifne +98 -> 108
/*      */     //   13: aload_2
/*      */     //   14: invokevirtual 1050	com/zimbra/cs/mime/ParsedMessage:getCalendarPartInfo	()Lcom/zimbra/cs/mime/ParsedMessage$CalendarPartInfo;
/*      */     //   17: astore 14
/*      */     //   19: aload 14
/*      */     //   21: ifnull +71 -> 92
/*      */     //   24: aload_0
/*      */     //   25: invokevirtual 115	com/zimbra/cs/mailbox/Mailbox:getAccount	()Lcom/zimbra/cs/account/Account;
/*      */     //   28: aload 14
/*      */     //   30: invokestatic 1053	com/zimbra/cs/mailbox/CalendarItem:isAcceptableInvite	(Lcom/zimbra/cs/account/Account;Lcom/zimbra/cs/mime/ParsedMessage$CalendarPartInfo;)Z
/*      */     //   33: ifeq +59 -> 92
/*      */     //   36: getstatic 1106	com/zimbra/common/calendar/ZCalendar$ICalTok:REPLY	Lcom/zimbra/common/calendar/ZCalendar$ICalTok;
/*      */     //   39: aload 14
/*      */     //   41: getfield 1172	com/zimbra/cs/mime/ParsedMessage$CalendarPartInfo:method	Lcom/zimbra/common/calendar/ZCalendar$ICalTok;
/*      */     //   44: invokevirtual 1173	com/zimbra/common/calendar/ZCalendar$ICalTok:equals	(Ljava/lang/Object;)Z
/*      */     //   47: ifeq +17 -> 64
/*      */     //   50: aload_0
/*      */     //   51: aload_1
/*      */     //   52: aload 14
/*      */     //   54: getfield 1174	com/zimbra/cs/mime/ParsedMessage$CalendarPartInfo:cal	Lcom/zimbra/common/calendar/ZCalendar$ZVCalendar;
/*      */     //   57: aconst_null
/*      */     //   58: invokespecial 1175	com/zimbra/cs/mailbox/Mailbox:processICalReplies	(Lcom/zimbra/cs/mailbox/OperationContext;Lcom/zimbra/common/calendar/ZCalendar$ZVCalendar;Ljava/lang/String;)V
/*      */     //   61: goto +31 -> 92
/*      */     //   64: getstatic 1176	com/zimbra/common/calendar/ZCalendar$ICalTok:COUNTER	Lcom/zimbra/common/calendar/ZCalendar$ICalTok;
/*      */     //   67: aload 14
/*      */     //   69: getfield 1172	com/zimbra/cs/mime/ParsedMessage$CalendarPartInfo:method	Lcom/zimbra/common/calendar/ZCalendar$ICalTok;
/*      */     //   72: invokevirtual 1173	com/zimbra/common/calendar/ZCalendar$ICalTok:equals	(Ljava/lang/Object;)Z
/*      */     //   75: ifeq +17 -> 92
/*      */     //   78: aload_0
/*      */     //   79: aload_1
/*      */     //   80: aload 14
/*      */     //   82: getfield 1174	com/zimbra/cs/mime/ParsedMessage$CalendarPartInfo:cal	Lcom/zimbra/common/calendar/ZCalendar$ZVCalendar;
/*      */     //   85: aload_2
/*      */     //   86: invokevirtual 1177	com/zimbra/cs/mime/ParsedMessage:getSender	()Ljava/lang/String;
/*      */     //   89: invokespecial 1175	com/zimbra/cs/mailbox/Mailbox:processICalReplies	(Lcom/zimbra/cs/mailbox/OperationContext;Lcom/zimbra/common/calendar/ZCalendar$ZVCalendar;Ljava/lang/String;)V
/*      */     //   92: goto +16 -> 108
/*      */     //   95: astore 14
/*      */     //   97: getstatic 810	com/zimbra/common/util/ZimbraLog:calendar	Lcom/zimbra/common/util/Log;
/*      */     //   100: ldc_w 1178
/*      */     //   103: aload 14
/*      */     //   105: invokevirtual 238	com/zimbra/common/util/Log:warn	(Ljava/lang/Object;Ljava/lang/Throwable;)V
/*      */     //   108: aload 11
/*      */     //   110: ifnonnull +12 -> 122
/*      */     //   113: new 1155	com/zimbra/cs/mailbox/DeliveryContext
/*      */     //   116: dup
/*      */     //   117: invokespecial 1156	com/zimbra/cs/mailbox/DeliveryContext:<init>	()V
/*      */     //   120: astore 11
/*      */     //   122: invokestatic 478	com/zimbra/cs/store/StoreManager:getInstance	()Lcom/zimbra/cs/store/StoreManager;
/*      */     //   125: astore 14
/*      */     //   127: aload 11
/*      */     //   129: invokevirtual 1179	com/zimbra/cs/mailbox/DeliveryContext:getIncomingBlob	()Lcom/zimbra/cs/store/Blob;
/*      */     //   132: astore 15
/*      */     //   134: iconst_0
/*      */     //   135: istore 16
/*      */     //   137: aload 15
/*      */     //   139: ifnonnull +50 -> 189
/*      */     //   142: aconst_null
/*      */     //   143: astore 17
/*      */     //   145: aload_2
/*      */     //   146: invokevirtual 1180	com/zimbra/cs/mime/ParsedMessage:getRawInputStream	()Ljava/io/InputStream;
/*      */     //   149: astore 17
/*      */     //   151: aload 14
/*      */     //   153: aload 17
/*      */     //   155: invokevirtual 1142	com/zimbra/cs/store/StoreManager:storeIncoming	(Ljava/io/InputStream;)Lcom/zimbra/cs/store/Blob;
/*      */     //   158: astore 15
/*      */     //   160: aload 17
/*      */     //   162: invokestatic 1181	com/zimbra/common/util/ByteUtil:closeStream	(Ljava/io/InputStream;)V
/*      */     //   165: goto +13 -> 178
/*      */     //   168: astore 18
/*      */     //   170: aload 17
/*      */     //   172: invokestatic 1181	com/zimbra/common/util/ByteUtil:closeStream	(Ljava/io/InputStream;)V
/*      */     //   175: aload 18
/*      */     //   177: athrow
/*      */     //   178: aload 11
/*      */     //   180: aload 15
/*      */     //   182: invokevirtual 1157	com/zimbra/cs/mailbox/DeliveryContext:setIncomingBlob	(Lcom/zimbra/cs/store/Blob;)Lcom/zimbra/cs/mailbox/DeliveryContext;
/*      */     //   185: pop
/*      */     //   186: iconst_1
/*      */     //   187: istore 16
/*      */     //   189: aload 14
/*      */     //   191: aload 15
/*      */     //   193: aload_0
/*      */     //   194: invokevirtual 1182	com/zimbra/cs/store/StoreManager:stage	(Lcom/zimbra/cs/store/Blob;Lcom/zimbra/cs/mailbox/Mailbox;)Lcom/zimbra/cs/store/StagedBlob;
/*      */     //   197: astore 17
/*      */     //   199: aload_0
/*      */     //   200: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   203: invokevirtual 48	com/zimbra/cs/mailbox/MailboxLock:lock	()V
/*      */     //   206: aload_0
/*      */     //   207: aload_1
/*      */     //   208: aload_2
/*      */     //   209: iload_3
/*      */     //   210: iload 4
/*      */     //   212: iload 5
/*      */     //   214: aload 6
/*      */     //   216: iload 7
/*      */     //   218: aload 8
/*      */     //   220: aload 9
/*      */     //   222: aload 10
/*      */     //   224: aload 11
/*      */     //   226: aload 17
/*      */     //   228: invokespecial 1183	com/zimbra/cs/mailbox/Mailbox:addMessageInternal	(Lcom/zimbra/cs/mailbox/OperationContext;Lcom/zimbra/cs/mime/ParsedMessage;IZI[Ljava/lang/String;ILjava/lang/String;Lcom/zimbra/cs/mailbox/Message$DraftInfo;Lcom/zimbra/cs/mailbox/MailItem$CustomMetadata;Lcom/zimbra/cs/mailbox/DeliveryContext;Lcom/zimbra/cs/store/StagedBlob;)Lcom/zimbra/cs/mailbox/Message;
/*      */     //   231: astore 18
/*      */     //   233: iload 16
/*      */     //   235: ifeq +14 -> 249
/*      */     //   238: aload 14
/*      */     //   240: aload 11
/*      */     //   242: invokevirtual 1179	com/zimbra/cs/mailbox/DeliveryContext:getIncomingBlob	()Lcom/zimbra/cs/store/Blob;
/*      */     //   245: invokevirtual 1159	com/zimbra/cs/store/StoreManager:quietDelete	(Lcom/zimbra/cs/store/Blob;)Z
/*      */     //   248: pop
/*      */     //   249: aload 14
/*      */     //   251: aload 17
/*      */     //   253: invokevirtual 1184	com/zimbra/cs/store/StoreManager:quietDelete	(Lcom/zimbra/cs/store/StagedBlob;)Z
/*      */     //   256: pop
/*      */     //   257: aload_0
/*      */     //   258: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   261: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   264: getstatic 1170	com/zimbra/cs/stats/ZimbraPerf:STOPWATCH_MBOX_ADD_MSG	Lcom/zimbra/common/stats/StopWatch;
/*      */     //   267: lload 12
/*      */     //   269: invokevirtual 1185	com/zimbra/common/stats/StopWatch:stop	(J)J
/*      */     //   272: pop2
/*      */     //   273: aload 18
/*      */     //   275: areturn
/*      */     //   276: astore 19
/*      */     //   278: iload 16
/*      */     //   280: ifeq +14 -> 294
/*      */     //   283: aload 14
/*      */     //   285: aload 11
/*      */     //   287: invokevirtual 1179	com/zimbra/cs/mailbox/DeliveryContext:getIncomingBlob	()Lcom/zimbra/cs/store/Blob;
/*      */     //   290: invokevirtual 1159	com/zimbra/cs/store/StoreManager:quietDelete	(Lcom/zimbra/cs/store/Blob;)Z
/*      */     //   293: pop
/*      */     //   294: aload 14
/*      */     //   296: aload 17
/*      */     //   298: invokevirtual 1184	com/zimbra/cs/store/StoreManager:quietDelete	(Lcom/zimbra/cs/store/StagedBlob;)Z
/*      */     //   301: pop
/*      */     //   302: aload 19
/*      */     //   304: athrow
/*      */     //   305: astore 20
/*      */     //   307: aload_0
/*      */     //   308: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   311: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   314: getstatic 1170	com/zimbra/cs/stats/ZimbraPerf:STOPWATCH_MBOX_ADD_MSG	Lcom/zimbra/common/stats/StopWatch;
/*      */     //   317: lload 12
/*      */     //   319: invokevirtual 1185	com/zimbra/common/stats/StopWatch:stop	(J)J
/*      */     //   322: pop2
/*      */     //   323: aload 20
/*      */     //   325: athrow
/*      */     // Line number table:
/*      */     //   Java source line #5751	-> byte code offset #0
/*      */     //   Java source line #5766	-> byte code offset #8
/*      */     //   Java source line #5768	-> byte code offset #13
/*      */     //   Java source line #5769	-> byte code offset #19
/*      */     //   Java source line #5770	-> byte code offset #36
/*      */     //   Java source line #5771	-> byte code offset #50
/*      */     //   Java source line #5772	-> byte code offset #64
/*      */     //   Java source line #5773	-> byte code offset #78
/*      */     //   Java source line #5778	-> byte code offset #92
/*      */     //   Java source line #5776	-> byte code offset #95
/*      */     //   Java source line #5777	-> byte code offset #97
/*      */     //   Java source line #5782	-> byte code offset #108
/*      */     //   Java source line #5783	-> byte code offset #113
/*      */     //   Java source line #5786	-> byte code offset #122
/*      */     //   Java source line #5787	-> byte code offset #127
/*      */     //   Java source line #5788	-> byte code offset #134
/*      */     //   Java source line #5790	-> byte code offset #137
/*      */     //   Java source line #5791	-> byte code offset #142
/*      */     //   Java source line #5793	-> byte code offset #145
/*      */     //   Java source line #5794	-> byte code offset #151
/*      */     //   Java source line #5796	-> byte code offset #160
/*      */     //   Java source line #5797	-> byte code offset #165
/*      */     //   Java source line #5796	-> byte code offset #168
/*      */     //   Java source line #5798	-> byte code offset #178
/*      */     //   Java source line #5799	-> byte code offset #186
/*      */     //   Java source line #5802	-> byte code offset #189
/*      */     //   Java source line #5804	-> byte code offset #199
/*      */     //   Java source line #5807	-> byte code offset #206
/*      */     //   Java source line #5810	-> byte code offset #233
/*      */     //   Java source line #5811	-> byte code offset #238
/*      */     //   Java source line #5813	-> byte code offset #249
/*      */     //   Java source line #5816	-> byte code offset #257
/*      */     //   Java source line #5817	-> byte code offset #264
/*      */     //   Java source line #5810	-> byte code offset #276
/*      */     //   Java source line #5811	-> byte code offset #283
/*      */     //   Java source line #5813	-> byte code offset #294
/*      */     //   Java source line #5816	-> byte code offset #305
/*      */     //   Java source line #5817	-> byte code offset #314
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	326	0	this	Mailbox
/*      */     //   0	326	1	octxt	OperationContext
/*      */     //   0	326	2	pm	ParsedMessage
/*      */     //   0	326	3	folderId	int
/*      */     //   0	326	4	noICal	boolean
/*      */     //   0	326	5	flags	int
/*      */     //   0	326	6	tags	String[]
/*      */     //   0	326	7	conversationId	int
/*      */     //   0	326	8	rcptEmail	String
/*      */     //   0	326	9	dinfo	Message.DraftInfo
/*      */     //   0	326	10	customData	MailItem.CustomMetadata
/*      */     //   0	326	11	dctxt	DeliveryContext
/*      */     //   6	312	12	start	long
/*      */     //   17	64	14	cpi	ParsedMessage.CalendarPartInfo
/*      */     //   95	9	14	e	Exception
/*      */     //   125	170	14	sm	StoreManager
/*      */     //   132	60	15	blob	Blob
/*      */     //   135	144	16	deleteIncoming	boolean
/*      */     //   143	28	17	in	InputStream
/*      */     //   197	100	17	staged	StagedBlob
/*      */     //   168	8	18	localObject1	Object
/*      */     //   231	43	18	localMessage	Message
/*      */     //   276	27	19	localObject2	Object
/*      */     //   305	19	20	localObject3	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   13	92	95	java/lang/Exception
/*      */     //   145	160	168	finally
/*      */     //   168	170	168	finally
/*      */     //   206	233	276	finally
/*      */     //   276	278	276	finally
/*      */     //   206	257	305	finally
/*      */     //   276	307	305	finally
/*      */   }
/*      */   
/*      */   private Message addMessageInternal(OperationContext octxt, ParsedMessage pm, int folderId, boolean noICal, int flags, String[] tags, int conversationId, String rcptEmail, Message.DraftInfo dinfo, MailItem.CustomMetadata customData, DeliveryContext dctxt, StagedBlob staged)
/*      */     throws IOException, ServiceException
/*      */   {
/* 5825 */     assert (this.lock.isWriteLockedByCurrentThread());
/* 5826 */     if (pm == null) {
/* 5827 */       throw ServiceException.INVALID_REQUEST("null ParsedMessage when adding message to mailbox " + this.mId, null);
/*      */     }
/*      */     
/* 5830 */     if (Math.abs(conversationId) <= 18) {
/* 5831 */       conversationId = -1;
/*      */     }
/*      */     
/* 5834 */     CreateMessage redoPlayer = octxt == null ? null : (CreateMessage)octxt.getPlayer();
/* 5835 */     boolean needRedo = needRedo(octxt, redoPlayer);
/* 5836 */     boolean isRedo = redoPlayer != null;
/*      */     
/* 5838 */     Blob blob = dctxt.getIncomingBlob();
/* 5839 */     if (blob == null) {
/* 5840 */       throw ServiceException.FAILURE("Incoming blob not found.", null);
/*      */     }
/*      */     
/*      */ 
/* 5844 */     pm.setDefaultCharset(getAccount().getPrefMailDefaultCharset());
/*      */     
/*      */ 
/* 5847 */     String msgidHeader = pm.getMessageID();
/* 5848 */     boolean isSent = (flags & Flag.BITMASK_FROM_ME) != 0;
/* 5849 */     if ((!isRedo) && (msgidHeader != null) && (!isSent) && (this.mSentMessageIDs.containsKey(msgidHeader))) {
/* 5850 */       Integer sentMsgID = (Integer)this.mSentMessageIDs.get(msgidHeader);
/* 5851 */       if (conversationId == -1) {
/* 5852 */         conversationId = getConversationIdFromReferent(pm.getMimeMessage(), sentMsgID.intValue());
/* 5853 */         ZimbraLog.mailbox.debug("duplicate detected but not deduped (%s); will try to slot into conversation %d", new Object[] { msgidHeader, Integer.valueOf(conversationId) });
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 5859 */     flags &= (Flag.FLAGS_SYSTEM ^ 0xFFFFFFFF | Flag.BITMASK_DRAFT | Flag.BITMASK_FROM_ME | Flag.BITMASK_POST);
/*      */     
/* 5861 */     flags &= (Flag.FLAGS_GENERIC | Flag.FLAGS_MESSAGE);
/*      */     String digest;
/*      */     int msgSize;
/*      */     try
/*      */     {
/* 5866 */       digest = blob.getDigest();
/* 5867 */       msgSize = (int)blob.getRawSize();
/*      */     } catch (IOException e) {
/* 5869 */       throw ServiceException.FAILURE("Unable to get message properties.", e);
/*      */     }
/*      */     
/* 5872 */     CreateMessage redoRecorder = new CreateMessage(this.mId, rcptEmail, pm.getReceivedDate(), dctxt.getShared(), digest, msgSize, folderId, noICal, flags, tags, customData);
/*      */     
/* 5874 */     StoreIncomingBlob storeRedoRecorder = null;
/*      */     
/*      */ 
/* 5877 */     boolean unread = (flags & Flag.BITMASK_UNREAD) > 0;
/* 5878 */     flags &= (Flag.BITMASK_UNREAD ^ 0xFFFFFFFF);
/*      */     
/*      */ 
/* 5881 */     if (pm.hasAttachments()) {
/* 5882 */       flags |= Flag.BITMASK_ATTACHED;
/*      */     } else {
/* 5884 */       flags &= (Flag.BITMASK_ATTACHED ^ 0xFFFFFFFF);
/*      */     }
/*      */     
/*      */ 
/* 5888 */     flags &= ((Flag.BITMASK_HIGH_PRIORITY | Flag.BITMASK_LOW_PRIORITY) ^ 0xFFFFFFFF);
/* 5889 */     flags |= pm.getPriorityBitmask();
/*      */     
/* 5891 */     boolean isSpam = folderId == 4;
/* 5892 */     boolean isDraft = (flags & Flag.BITMASK_DRAFT) != 0;
/*      */     
/*      */ 
/* 5895 */     if ((isDraft) && (!isRedo) && (conversationId == -1) && (dinfo != null) && (!Strings.isNullOrEmpty(dinfo.origId))) {
/*      */       try
/*      */       {
/* 5898 */         ItemId iid = new ItemId(dinfo.origId, getAccountId());
/* 5899 */         if ((iid.getId() > 0) && (iid.belongsTo(this))) {
/* 5900 */           conversationId = getMessageById(octxt, iid.getId()).getConversationId();
/*      */         }
/*      */       }
/*      */       catch (ServiceException e) {}
/*      */     }
/*      */     
/* 5906 */     Message msg = null;
/* 5907 */     boolean success = false;
/*      */     
/* 5909 */     MailItem.CustomMetadata.CustomMetadataList extended = MetadataCallback.preDelivery(pm);
/* 5910 */     if (customData != null) {
/* 5911 */       if (extended == null) {
/* 5912 */         extended = customData.asList();
/*      */       } else {
/* 5914 */         extended.addSection(customData);
/*      */       }
/*      */     }
/*      */     
/* 5918 */     Threader threader = pm.getThreader(this);
/* 5919 */     String subject = pm.getNormalizedSubject();
/*      */     try
/*      */     {
/* 5922 */       beginTransaction("addMessage", octxt, redoRecorder);
/* 5923 */       if (isRedo) {
/* 5924 */         rcptEmail = redoPlayer.getRcptEmail();
/*      */       }
/*      */       
/* 5927 */       Tag.NormalizedTags ntags = new Tag.NormalizedTags(this, tags);
/*      */       
/* 5929 */       Folder folder = getFolderById(folderId);
/*      */       
/*      */ 
/* 5932 */       if (!getAccount().isMailAllowReceiveButNotSendWhenOverQuota()) {
/* 5933 */         checkSizeChange(getSize() + staged.getSize());
/*      */       }
/*      */       
/*      */ 
/* 5937 */       int messageId = getNextItemId(!isRedo ? -1 : redoPlayer.getMessageId());
/*      */       
/* 5939 */       List<Conversation> mergeConvs = null;
/* 5940 */       Iterator i$; if (isRedo) {
/* 5941 */         conversationId = redoPlayer.getConvId();
/*      */         
/*      */ 
/* 5944 */         List<Integer> mergeConvIds = redoPlayer.getMergedConvIds();
/* 5945 */         mergeConvs = new ArrayList(mergeConvIds.size());
/* 5946 */         for (i$ = mergeConvIds.iterator(); i$.hasNext();) { int mergeId = ((Integer)i$.next()).intValue();
/*      */           try {
/* 5948 */             mergeConvs.add(getConversationById(mergeId));
/*      */           } catch (MailServiceException.NoSuchItemException nsie) {
/* 5950 */             ZimbraLog.mailbox.debug("could not find merge conversation %d", new Object[] { Integer.valueOf(mergeId) });
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 5956 */       Conversation conv = null;
/* 5957 */       if (threader.isEnabled()) {
/* 5958 */         boolean isReply = pm.isReply();
/* 5959 */         if (conversationId != -1)
/*      */         {
/*      */           try
/*      */           {
/* 5963 */             conv = getConversationById(conversationId);
/* 5964 */             ZimbraLog.mailbox.debug("fetched explicitly-specified conversation %d", new Object[] { Integer.valueOf(conv.getId()) });
/*      */           } catch (MailServiceException.NoSuchItemException nsie) {
/* 5966 */             if (!isRedo) {
/* 5967 */               ZimbraLog.mailbox.debug("could not find explicitly-specified conversation %d", new Object[] { Integer.valueOf(conversationId) });
/* 5968 */               conversationId = -1;
/*      */             }
/*      */           }
/* 5971 */         } else if ((!isRedo) && (!isSpam) && ((isReply) || ((!isSent) && (!subject.isEmpty())))) {
/* 5972 */           List<Conversation> matches = threader.lookupConversation();
/* 5973 */           if ((matches != null) && (!matches.isEmpty()))
/*      */           {
/* 5975 */             Collections.sort(matches, new MailItem.SortSizeDescending());
/* 5976 */             conv = (Conversation)matches.remove(0);
/* 5977 */             mergeConvs = matches;
/*      */           }
/*      */         }
/*      */       }
/* 5981 */       if ((conv != null) && (conv.isTagged(Flag.FlagInfo.MUTED)))
/*      */       {
/* 5983 */         unread = false;
/* 5984 */         flags |= Flag.BITMASK_MUTED;
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 5989 */       Conversation convTarget = (conv instanceof VirtualConversation) ? null : conv;
/* 5990 */       if (convTarget != null) {
/* 5991 */         ZimbraLog.mailbox.debug("  placing message in existing conversation %d", new Object[] { Integer.valueOf(convTarget.getId()) });
/*      */       }
/*      */       
/* 5994 */       ParsedMessage.CalendarPartInfo cpi = pm.getCalendarPartInfo();
/* 5995 */       ZCalendar.ZVCalendar iCal = null;
/* 5996 */       if ((cpi != null) && (CalendarItem.isAcceptableInvite(getAccount(), cpi))) {
/* 5997 */         iCal = cpi.cal;
/*      */       }
/* 5999 */       msg = Message.create(messageId, folder, convTarget, pm, staged, unread, flags, ntags, dinfo, noICal, iCal, extended);
/*      */       
/* 6001 */       redoRecorder.setMessageId(msg.getId());
/*      */       
/*      */ 
/* 6004 */       if ((threader.isEnabled()) && (convTarget == null)) {
/* 6005 */         if ((conv == null) && (conversationId == -1)) {
/* 6006 */           conv = VirtualConversation.create(this, msg);
/* 6007 */           ZimbraLog.mailbox.debug("placed message %d in vconv %d", new Object[] { Integer.valueOf(msg.getId()), Integer.valueOf(conv.getId()) });
/* 6008 */           redoRecorder.setConvFirstMsgId(-1);
/*      */         } else {
/* 6010 */           Message[] contents = null;
/* 6011 */           VirtualConversation vconv = null;
/* 6012 */           if (!isRedo) {
/* 6013 */             vconv = (VirtualConversation)conv;
/* 6014 */             contents = new Message[] { vconv.getMessage(), vconv == null ? new Message[] { msg } : msg };
/*      */           }
/*      */           else {
/* 6017 */             int convFirstMsgId = redoPlayer.getConvFirstMsgId();
/* 6018 */             Message convFirstMsg = null;
/*      */             
/* 6020 */             if (convFirstMsgId > 0) {
/*      */               try {
/* 6022 */                 convFirstMsg = getMessageById(octxt, redoPlayer.getConvFirstMsgId());
/*      */               } catch (MailServiceException e) {
/* 6024 */                 if (!"mail.NO_SUCH_MSG".equals(e.getCode())) {
/* 6025 */                   throw e;
/*      */                 }
/*      */               }
/*      */               
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 6036 */               if ((convFirstMsg != null) && (convFirstMsg.getConversationId() < 0)) {
/* 6037 */                 contents = new Message[] { convFirstMsg, msg };
/* 6038 */                 vconv = new VirtualConversation(this, convFirstMsg);
/*      */               }
/*      */             }
/* 6041 */             if (contents == null) {
/* 6042 */               contents = new Message[] { msg };
/*      */             }
/*      */           }
/* 6045 */           redoRecorder.setConvFirstMsgId(vconv != null ? vconv.getMessageId() : -1);
/* 6046 */           conv = createConversation(conversationId, contents);
/* 6047 */           if (vconv != null) {
/* 6048 */             ZimbraLog.mailbox.debug("removed vconv %d", new Object[] { Integer.valueOf(vconv.getId()) });
/* 6049 */             vconv.removeChild(vconv.getMessage());
/*      */           }
/*      */           
/*      */ 
/* 6053 */           if (contents.length == 2) {
/* 6054 */             threader.changeThreadingTargets(contents[0], conv);
/*      */           }
/*      */         }
/*      */       }
/*      */       else {
/* 6059 */         redoRecorder.setConvFirstMsgId(-1);
/*      */       }
/* 6061 */       redoRecorder.setConvId((conv != null) && (!(conv instanceof VirtualConversation)) ? conv.getId() : -1);
/*      */       
/* 6063 */       if ((!isSpam) && (!isDraft)) {
/* 6064 */         threader.recordAddedMessage(conv);
/*      */       }
/*      */       
/* 6067 */       if ((conv != null) && (mergeConvs != null)) {
/* 6068 */         redoRecorder.setMergedConversations(mergeConvs);
/* 6069 */         for (Conversation smaller : mergeConvs) {
/* 6070 */           ZimbraLog.mailbox.info("merging conversation %d for references threading", new Object[] { Integer.valueOf(smaller.getId()) });
/* 6071 */           conv.merge(smaller);
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 6076 */       threader.reset();
/*      */       
/*      */ 
/* 6079 */       if (dctxt.getShared()) {
/* 6080 */         if ((dctxt.isFirst()) && (needRedo))
/*      */         {
/*      */ 
/* 6083 */           storeRedoRecorder = new StoreIncomingBlob(digest, msgSize, dctxt.getMailboxIdList());
/* 6084 */           storeRedoRecorder.start(getOperationTimestampMillis());
/* 6085 */           storeRedoRecorder.setBlobBodyInfo(blob.getFile());
/* 6086 */           storeRedoRecorder.log();
/*      */         }
/*      */         
/* 6089 */         redoRecorder.setMessageLinkInfo(blob.getPath());
/*      */       }
/*      */       else {
/* 6092 */         redoRecorder.setMessageBodyInfo(blob.getFile());
/*      */       }
/*      */       
/*      */ 
/* 6096 */       MailboxBlob mblob = StoreManager.getInstance().link(staged, this, messageId, getOperationChangeID());
/* 6097 */       markOtherItemDirty(mblob);
/*      */       
/*      */ 
/* 6100 */       msg.updateBlobData(mblob);
/*      */       
/* 6102 */       if (dctxt.getMailboxBlob() == null)
/*      */       {
/*      */ 
/* 6105 */         dctxt.setMailboxBlob(mblob);
/*      */       }
/*      */       
/*      */ 
/* 6109 */       this.index.add(msg);
/* 6110 */       success = true;
/*      */       
/*      */       try
/*      */       {
/* 6114 */         Notification.getInstance().interceptIfNecessary(this, pm.getMimeMessage(), "add message", folder);
/*      */       } catch (ServiceException e) {
/* 6116 */         ZimbraLog.mailbox.error("unable to send legal intercept message", e);
/*      */       }
/*      */     } finally {
/* 6119 */       if (storeRedoRecorder != null) {
/* 6120 */         if (success) {
/* 6121 */           storeRedoRecorder.commit();
/*      */         } else {
/* 6123 */           storeRedoRecorder.abort();
/*      */         }
/*      */       }
/*      */       
/* 6127 */       endTransaction(success);
/*      */       
/* 6129 */       if (success)
/*      */       {
/*      */ 
/*      */ 
/* 6133 */         dctxt.setFirst(false);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 6138 */     if ((isSent) && (!isRedo) && (msgidHeader != null)) {
/* 6139 */       this.mSentMessageIDs.put(msgidHeader, Integer.valueOf(msg.getId()));
/*      */     }
/*      */     
/* 6142 */     return msg;
/*      */   }
/*      */   
/*      */   public List<Conversation> lookupConversation(ParsedMessage pm) throws ServiceException {
/* 6146 */     boolean success = false;
/* 6147 */     beginTransaction("lookupConversation", null);
/*      */     try {
/* 6149 */       List<Conversation> result = pm.getThreader(this).lookupConversation();
/* 6150 */       success = true;
/* 6151 */       return result;
/*      */     } finally {
/* 6153 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public static String getHash(String subject) {
/*      */     try {
/* 6159 */       return ByteUtil.getSHA1Digest(Strings.nullToEmpty(subject).getBytes("utf-8"), true);
/*      */     } catch (UnsupportedEncodingException uee) {}
/* 6161 */     return ByteUtil.getSHA1Digest(Strings.nullToEmpty(subject).getBytes(), true);
/*      */   }
/*      */   
/*      */   void openConversation(Conversation conv, String subjectHash)
/*      */     throws ServiceException
/*      */   {
/* 6167 */     String hash = subjectHash != null ? subjectHash : getHash(conv.getNormalizedSubject());
/* 6168 */     conv.open(hash);
/* 6169 */     markOtherItemDirty(hash);
/* 6170 */     this.mConvHashes.put(hash, Integer.valueOf(conv.getId()));
/*      */   }
/*      */   
/*      */   void closeConversation(Conversation conv, String subjectHash) throws ServiceException
/*      */   {
/* 6175 */     String hash = subjectHash != null ? subjectHash : getHash(conv.getNormalizedSubject());
/* 6176 */     conv.close(hash);
/* 6177 */     this.mConvHashes.remove(hash);
/*      */   }
/*      */   
/*      */   Conversation createConversation(int convId, Message... contents) throws ServiceException
/*      */   {
/* 6182 */     int id = Math.max(convId, -1);
/* 6183 */     Conversation conv = Conversation.create(this, getNextItemId(id), contents);
/* 6184 */     if (ZimbraLog.mailbox.isDebugEnabled()) {
/* 6185 */       StringBuilder sb = new StringBuilder();
/* 6186 */       for (int i = 0; i < contents.length; i++) {
/* 6187 */         sb.append(i == 0 ? "" : ",").append(contents[i].getId());
/*      */       }
/* 6189 */       ZimbraLog.mailbox.debug("  created conv " + conv.getId() + " holding msg(s): " + sb);
/*      */     }
/* 6191 */     return conv;
/*      */   }
/*      */   
/*      */   public Message saveDraft(OperationContext octxt, ParsedMessage pm, int id) throws IOException, ServiceException {
/* 6195 */     return saveDraft(octxt, pm, id, null, null, null, null, 0L);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Message saveDraft(OperationContext octxt, ParsedMessage pm, int id, String origId, String replyType, String identityId, String accountId, long autoSendTime)
/*      */     throws IOException, ServiceException
/*      */   {
/* 6208 */     Message.DraftInfo dinfo = null;
/* 6209 */     if (((replyType != null) && (origId != null)) || (identityId != null) || (accountId != null) || (autoSendTime != 0L)) {
/* 6210 */       dinfo = new Message.DraftInfo(replyType, origId, identityId, accountId, autoSendTime);
/*      */     }
/*      */     
/* 6213 */     if (id == -1)
/*      */     {
/* 6215 */       return addMessage(octxt, pm, 6, true, Flag.BITMASK_DRAFT | Flag.BITMASK_FROM_ME, null, -1, ":API:", dinfo, null, null);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 6220 */     StoreManager sm = StoreManager.getInstance();
/*      */     
/* 6222 */     InputStream is = pm.getRawInputStream();
/*      */     StagedBlob staged;
/* 6224 */     try { staged = sm.stage(is, this);
/*      */     } finally {
/* 6226 */       ByteUtil.closeStream(is);
/*      */     }
/*      */     
/* 6229 */     String digest = staged.getDigest();
/* 6230 */     int size = (int)staged.getSize();
/*      */     
/* 6232 */     SaveDraft redoRecorder = new SaveDraft(this.mId, id, digest, size);
/* 6233 */     InputStream redoStream = null;
/*      */     
/* 6235 */     boolean success = false;
/*      */     try {
/* 6237 */       beginTransaction("saveDraft", octxt, redoRecorder);
/* 6238 */       SaveDraft redoPlayer = (SaveDraft)currentChange().getRedoPlayer();
/*      */       
/* 6240 */       Message msg = getMessageById(id);
/* 6241 */       if (!msg.isTagged(Flag.FlagInfo.DRAFT)) {
/* 6242 */         throw MailServiceException.IMMUTABLE_OBJECT(id);
/*      */       }
/* 6244 */       if (!checkItemChangeID(msg)) {
/* 6245 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/*      */       
/*      */ 
/* 6249 */       int imapID = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getImapId());
/* 6250 */       redoRecorder.setImapId(imapID);
/* 6251 */       redoRecorder.setMessageBodyInfo(new ParsedMessageDataSource(pm), size);
/*      */       
/* 6253 */       msg.setDraftAutoSendTime(autoSendTime);
/*      */       
/* 6255 */       if (dinfo != null) {
/* 6256 */         if (replyType != null) {
/* 6257 */           msg.setDraftReplyType(replyType);
/*      */         }
/* 6259 */         if (origId != null) {
/* 6260 */           msg.setDraftOrigId(origId);
/*      */         }
/* 6262 */         if (identityId != null) {
/* 6263 */           msg.setDraftIdentityId(identityId);
/*      */         }
/* 6265 */         if (accountId != null) {
/* 6266 */           msg.setDraftAccountId(accountId);
/*      */         }
/* 6268 */         if (autoSendTime != 0L) {
/* 6269 */           msg.setDraftAutoSendTime(autoSendTime);
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 6274 */       msg.setContent(staged, pm);
/*      */       
/* 6276 */       this.index.add(msg);
/*      */       
/* 6278 */       success = true;
/*      */       try
/*      */       {
/* 6281 */         Notification.getInstance().interceptIfNecessary(this, pm.getMimeMessage(), "save draft", msg.getFolder());
/*      */       } catch (ServiceException e) {
/* 6283 */         ZimbraLog.mailbox.error("Unable to send lawful intercept message.", e);
/*      */       }
/*      */       
/* 6286 */       return msg;
/*      */     } finally {
/* 6288 */       endTransaction(success);
/*      */       
/* 6290 */       ByteUtil.closeStream(redoStream);
/* 6291 */       sm.quietDelete(staged);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void modifyPartStat(OperationContext octxt, int calItemId, RecurId recurId, String cnStr, String addressStr, String cutypeStr, String roleStr, String partStatStr, Boolean rsvp, int seqNo, long dtStamp)
/*      */     throws ServiceException
/*      */   {
/* 6303 */     ModifyInvitePartStat redoRecorder = new ModifyInvitePartStat(this.mId, calItemId, recurId, cnStr, addressStr, cutypeStr, roleStr, partStatStr, rsvp, seqNo, dtStamp);
/*      */     
/*      */ 
/* 6306 */     boolean success = false;
/*      */     try {
/* 6308 */       beginTransaction("updateInvitePartStat", octxt, redoRecorder);
/* 6309 */       CalendarItem calItem = getCalendarItemById(calItemId);
/* 6310 */       Account acct = getAccount();
/* 6311 */       markItemModified(calItem, 131072);
/* 6312 */       calItem.modifyPartStat(acct, recurId, cnStr, addressStr, cutypeStr, roleStr, partStatStr, rsvp, seqNo, dtStamp);
/* 6313 */       success = true;
/*      */     } finally {
/* 6315 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<Integer> resetImapUid(OperationContext octxt, List<Integer> itemIds) throws ServiceException {
/* 6320 */     SetImapUid redoRecorder = new SetImapUid(this.mId, itemIds);
/*      */     
/* 6322 */     List<Integer> newIds = new ArrayList();
/* 6323 */     boolean success = false;
/*      */     try {
/* 6325 */       beginTransaction("resetImapUid", octxt, redoRecorder);
/* 6326 */       SetImapUid redoPlayer = (SetImapUid)currentChange().getRedoPlayer();
/*      */       
/* 6328 */       for (Iterator i$ = itemIds.iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 6329 */         MailItem item = getItemById(id, MailItem.Type.UNKNOWN);
/* 6330 */         int imapId = redoPlayer == null ? -1 : redoPlayer.getImapUid(id);
/* 6331 */         item.setImapUid(getNextItemId(imapId));
/* 6332 */         redoRecorder.setImapUid(item.getId(), item.getImapUid());
/* 6333 */         newIds.add(Integer.valueOf(item.getImapUid()));
/*      */       }
/* 6335 */       success = true;
/* 6336 */       return newIds;
/*      */     } finally {
/* 6338 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   void resetIndex()
/*      */     throws ServiceException
/*      */   {
/* 6346 */     assert (this.lock.isWriteLockedByCurrentThread());
/*      */     
/* 6348 */     boolean success = false;
/*      */     try {
/* 6350 */       beginTransaction("resetIndex", null);
/* 6351 */       DbMailItem.resetIndexId(getOperationConnection(), this);
/* 6352 */       success = true;
/*      */     } finally {
/* 6354 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setColor(OperationContext octxt, int itemId, MailItem.Type type, byte color) throws ServiceException {
/* 6359 */     setColor(octxt, new int[] { itemId }, type, color);
/*      */   }
/*      */   
/*      */   public void setColor(OperationContext octxt, int[] itemIds, MailItem.Type type, byte color) throws ServiceException
/*      */   {
/* 6364 */     setColor(octxt, itemIds, type, new Color(color));
/*      */   }
/*      */   
/*      */   public void setColor(OperationContext octxt, int[] itemIds, MailItem.Type type, Color color) throws ServiceException
/*      */   {
/* 6369 */     ColorItem redoRecorder = new ColorItem(this.mId, itemIds, type, color);
/*      */     
/* 6371 */     boolean success = false;
/*      */     try {
/* 6373 */       beginTransaction("setColor", octxt, redoRecorder);
/*      */       
/* 6375 */       MailItem[] items = getItemById(itemIds, type);
/* 6376 */       for (MailItem item : items) {
/* 6377 */         if (!checkItemChangeID(item)) {
/* 6378 */           throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */         }
/*      */       }
/* 6381 */       for (MailItem item : items) {
/* 6382 */         item.setColor(color);
/*      */       }
/* 6384 */       success = true;
/*      */     } finally {
/* 6386 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setCustomData(OperationContext octxt, int itemId, MailItem.Type type, MailItem.CustomMetadata custom) throws ServiceException
/*      */   {
/* 6392 */     String key = custom.getSectionKey();
/* 6393 */     if (MetadataCallback.isSectionRegistered(key)) {
/* 6394 */       throw ServiceException.PERM_DENIED("custom metadata section '" + key + "' may only be calculated, not set");
/*      */     }
/* 6396 */     SetCustomData redoRecorder = new SetCustomData(this.mId, itemId, type, custom);
/*      */     
/* 6398 */     boolean success = false;
/*      */     try {
/* 6400 */       beginTransaction("setCustomData", octxt, redoRecorder);
/*      */       
/* 6402 */       MailItem item = checkAccess(getItemById(itemId, type));
/* 6403 */       if (!checkItemChangeID(item)) {
/* 6404 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/* 6406 */       item.setCustomData(custom);
/* 6407 */       success = true;
/*      */     } finally {
/* 6409 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setDate(OperationContext octxt, int itemId, MailItem.Type type, long date) throws ServiceException {
/* 6414 */     DateItem redoRecorder = new DateItem(this.mId, itemId, type, date);
/*      */     
/* 6416 */     boolean success = false;
/*      */     try {
/* 6418 */       beginTransaction("setDate", octxt, redoRecorder);
/*      */       
/* 6420 */       MailItem item = getItemById(itemId, type);
/* 6421 */       if (!checkItemChangeID(item)) {
/* 6422 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/*      */       
/* 6425 */       item.setDate(date);
/* 6426 */       success = true;
/*      */     } finally {
/* 6428 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void alterTag(OperationContext octxt, int itemId, MailItem.Type type, Flag.FlagInfo finfo, boolean addTag, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6435 */     alterTag(octxt, new int[] { itemId }, type, finfo, addTag, tcon);
/*      */   }
/*      */   
/*      */   public void alterTag(OperationContext octxt, int[] itemIds, MailItem.Type type, Flag.FlagInfo finfo, boolean addTag, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6441 */     AlterItemTag redoRecorder = new AlterItemTag(this.mId, itemIds, type, finfo.flagName, addTag, tcon);
/*      */     
/* 6443 */     boolean success = false;
/*      */     try {
/* 6445 */       beginTransaction("alterTag", octxt, redoRecorder);
/* 6446 */       setOperationTargetConstraint(tcon);
/*      */       
/* 6448 */       alterTag(itemIds, type, finfo.toFlag(this), addTag);
/* 6449 */       success = true;
/*      */     } finally {
/* 6451 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void alterTag(OperationContext octxt, int itemId, MailItem.Type type, String tagName, boolean addTag, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6458 */     alterTag(octxt, new int[] { itemId }, type, tagName, addTag, tcon);
/*      */   }
/*      */   
/*      */   public void alterTag(OperationContext octxt, int[] itemIds, MailItem.Type type, String tagName, boolean addTag, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6464 */     AlterItemTag redoRecorder = new AlterItemTag(this.mId, itemIds, type, tagName, addTag, tcon);
/*      */     
/* 6466 */     boolean success = false;
/*      */     try {
/* 6468 */       beginTransaction("alterTag", octxt, redoRecorder);
/* 6469 */       setOperationTargetConstraint(tcon);
/*      */       Tag tag;
/*      */       try
/*      */       {
/* 6473 */         tag = getTagByName(tagName);
/*      */       } catch (MailServiceException.NoSuchItemException nsie) {
/* 6475 */         if (tagName.startsWith("\\")) {
/* 6476 */           throw nsie;
/*      */         }
/* 6478 */         Tag.NormalizedTags ntags = new Tag.NormalizedTags(this, new String[] { tagName }, addTag);
/* 6479 */         if (ntags.getTags().length == 0) {
/* 6480 */           success = true; return;
/*      */         }
/*      */         
/* 6483 */         tag = getTagByName(ntags.getTags()[0]);
/*      */       }
/*      */       
/* 6486 */       alterTag(itemIds, type, tag, addTag);
/* 6487 */       success = true;
/*      */     } finally {
/* 6489 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private void alterTag(int[] itemIds, MailItem.Type type, Tag tag, boolean addTag) throws ServiceException
/*      */   {
/* 6495 */     MailItem[] items = getItemById(itemIds, type);
/* 6496 */     for (MailItem item : items) {
/* 6497 */       if ((!(item instanceof Conversation)) && 
/* 6498 */         (!checkItemChangeID(item)) && ((item instanceof Tag))) {
/* 6499 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 6504 */     for (MailItem item : items) {
/* 6505 */       if (item != null)
/*      */       {
/*      */ 
/*      */ 
/* 6509 */         if (tag.getId() == Flag.ID_UNREAD) {
/* 6510 */           item.alterUnread(addTag);
/*      */         } else {
/* 6512 */           item.alterTag(tag, addTag);
/*      */         }
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   public void setTags(OperationContext octxt, int itemId, MailItem.Type type, int flags, String[] tags) throws ServiceException {
/* 6519 */     setTags(octxt, itemId, type, flags, tags, null);
/*      */   }
/*      */   
/*      */   public void setTags(OperationContext octxt, int itemId, MailItem.Type type, int flags, String[] tags, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6525 */     setTags(octxt, new int[] { itemId }, type, flags, tags, tcon);
/*      */   }
/*      */   
/*      */   public void setTags(OperationContext octxt, int[] itemIds, MailItem.Type type, int flags, String[] tags, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6531 */     if ((flags == Integer.MIN_VALUE) && (tags == MailItem.TAG_UNCHANGED)) {
/* 6532 */       return;
/*      */     }
/*      */     
/* 6535 */     SetItemTags redoRecorder = new SetItemTags(this.mId, itemIds, type, flags, tags, tcon);
/*      */     
/* 6537 */     boolean success = false;
/*      */     try {
/* 6539 */       beginTransaction("setTags", octxt, redoRecorder);
/* 6540 */       setOperationTargetConstraint(tcon);
/*      */       
/* 6542 */       MailItem[] items = getItemById(itemIds, type);
/* 6543 */       for (MailItem item : items) {
/* 6544 */         checkItemChangeID(item);
/*      */       }
/* 6546 */       Flag unreadFlag = getFlagById(Flag.ID_UNREAD);
/*      */       
/* 6548 */       Tag.NormalizedTags ntags = tags == MailItem.TAG_UNCHANGED ? null : new Tag.NormalizedTags(this, tags);
/*      */       
/* 6550 */       for (MailItem item : items) {
/* 6551 */         if (item != null)
/*      */         {
/*      */ 
/* 6554 */           int iflags = flags;
/* 6555 */           Tag.NormalizedTags itags = ntags;
/* 6556 */           if ((iflags & 0x80000000) != 0) {
/* 6557 */             iflags = item.getFlagBitmask();
/*      */           }
/* 6559 */           if (itags == null) {
/* 6560 */             itags = new Tag.NormalizedTags(item.getTags());
/*      */           }
/*      */           
/* 6563 */           boolean iunread = (iflags & Flag.BITMASK_UNREAD) > 0;
/* 6564 */           iflags &= (Flag.BITMASK_UNREAD ^ 0xFFFFFFFF);
/*      */           
/* 6566 */           item.setTags(iflags, itags);
/* 6567 */           if (unreadFlag.canTag(item)) {
/* 6568 */             item.alterUnread(iunread);
/*      */           }
/*      */         }
/*      */       }
/* 6572 */       success = true;
/*      */     } finally {
/* 6574 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public List<MailItem> recover(OperationContext octxt, int[] itemIds, MailItem.Type type, int folderId)
/*      */     throws ServiceException
/*      */   {
/* 6583 */     RecoverItem redoRecorder = new RecoverItem(this.mId, type, folderId);
/* 6584 */     boolean success = false;
/*      */     try {
/* 6586 */       beginTransaction("recover[]", octxt, redoRecorder);
/* 6587 */       List<MailItem> result = copyInternal(octxt, itemIds, type, folderId, true);
/* 6588 */       deleteFromDumpster(itemIds);
/* 6589 */       success = true;
/* 6590 */       return result;
/*      */     } finally {
/* 6592 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public MailItem copy(OperationContext octxt, int itemId, MailItem.Type type, int folderId) throws ServiceException
/*      */   {
/* 6598 */     return (MailItem)copy(octxt, new int[] { itemId }, type, folderId).get(0);
/*      */   }
/*      */   
/*      */   public List<MailItem> copy(OperationContext octxt, int[] itemIds, MailItem.Type type, int folderId) throws ServiceException
/*      */   {
/* 6603 */     CopyItem redoRecorder = new CopyItem(this.mId, type, folderId);
/* 6604 */     boolean success = false;
/*      */     try {
/* 6606 */       beginTransaction("copy[]", octxt, redoRecorder);
/* 6607 */       List<MailItem> result = copyInternal(octxt, itemIds, type, folderId, false);
/* 6608 */       success = true;
/* 6609 */       return result;
/*      */     } finally {
/* 6611 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private List<MailItem> copyInternal(OperationContext octxt, int[] itemIds, MailItem.Type type, int folderId, boolean fromDumpster)
/*      */     throws ServiceException
/*      */   {
/* 6618 */     CopyItem redoRecorder = (CopyItem)currentChange().getRedoRecorder();
/*      */     try {
/* 6620 */       if (fromDumpster) {
/* 6621 */         Folder trash = getFolderById(3);
/* 6622 */         if (!trash.canAccess((short)1)) {
/* 6623 */           throw ServiceException.PERM_DENIED("dumpster access denied");
/*      */         }
/*      */       }
/* 6626 */       CopyItem redoPlayer = (CopyItem)currentChange().getRedoPlayer();
/*      */       
/* 6628 */       List<MailItem> result = new ArrayList();
/*      */       
/* 6630 */       Folder folder = getFolderById(folderId);
/*      */       
/* 6632 */       MailItem[] items = getItemById(itemIds, type, fromDumpster);
/* 6633 */       for (MailItem item : items) {
/* 6634 */         checkItemChangeID(item);
/*      */       }
/* 6636 */       for (MailItem item : items)
/*      */       {
/*      */         MailItem copy;
/* 6639 */         if ((item instanceof Conversation))
/*      */         {
/* 6641 */           Conversation conv = (Conversation)item;
/* 6642 */           List<Message> msgs = new ArrayList((int)conv.getSize());
/* 6643 */           for (Message original : conv.getMessages())
/* 6644 */             if (original.canAccess((short)1))
/*      */             {
/*      */ 
/* 6647 */               int newId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getDestId(original.getId()));
/*      */               String uuid;
/* 6649 */               String uuid; if (redoPlayer != null) {
/* 6650 */                 uuid = redoPlayer.getDestUuid(original.getId()); } else { String uuid;
/* 6651 */                 if (fromDumpster)
/*      */                 {
/* 6653 */                   uuid = original.getUuid();
/*      */                 } else
/* 6655 */                   uuid = UUIDUtil.generateUUID();
/*      */               }
/* 6657 */               Message msg = (Message)original.copy(folder, newId, uuid, null);
/* 6658 */               msgs.add(msg);
/* 6659 */               redoRecorder.setDest(original.getId(), newId, msg.getUuid());
/*      */             }
/* 6661 */           if (msgs.isEmpty())
/* 6662 */             throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/* 6663 */           MailItem copy; if (msgs.size() == 1) {
/* 6664 */             copy = ((Message)msgs.get(0)).getParent();
/*      */           } else {
/* 6666 */             int newId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getDestId(conv.getId()));
/* 6667 */             MailItem copy = Conversation.create(this, newId, (Message[])msgs.toArray(new Message[msgs.size()]));
/* 6668 */             redoRecorder.setDest(conv.getId(), newId, copy.getUuid());
/*      */           }
/*      */         } else {
/* 6671 */           int newId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getDestId(item.getId()));
/*      */           String uuid;
/* 6673 */           String uuid; if (redoPlayer != null) {
/* 6674 */             uuid = redoPlayer.getDestUuid(item.getId()); } else { String uuid;
/* 6675 */             if (fromDumpster)
/*      */             {
/* 6677 */               uuid = item.getUuid();
/*      */             } else
/* 6679 */               uuid = UUIDUtil.generateUUID();
/*      */           }
/* 6681 */           int parentId = item.getParentId();
/* 6682 */           MailItem parent = null;
/* 6683 */           if (parentId > 0) {
/*      */             try {
/* 6685 */               parent = getItemById(parentId, MailItem.Type.UNKNOWN);
/*      */             }
/*      */             catch (MailServiceException.NoSuchItemException e) {}
/*      */           }
/*      */           
/* 6690 */           copy = item.copy(folder, newId, uuid, parent);
/* 6691 */           if (fromDumpster) {
/* 6692 */             for (MailItem.UnderlyingData data : DbMailItem.getByParent(item, SortBy.DATE_DESC, -1, true)) {
/* 6693 */               MailItem child = getItem(data);
/* 6694 */               Folder destination = child.getType() == MailItem.Type.COMMENT ? getFolderById(17) : folder;
/* 6695 */               child.copy(destination, getNextItemId(-1), child.getUuid(), copy);
/*      */             }
/*      */           }
/* 6698 */           redoRecorder.setDest(item.getId(), newId, copy.getUuid());
/*      */         }
/*      */         
/* 6701 */         result.add(copy);
/*      */       }
/* 6703 */       return result;
/*      */     } catch (IOException e) {
/* 6705 */       throw ServiceException.FAILURE("IOException while copying items", e);
/*      */     }
/*      */   }
/*      */   
/*      */   public List<MailItem> imapCopy(OperationContext octxt, int[] itemIds, MailItem.Type type, int folderId)
/*      */     throws IOException, ServiceException
/*      */   {
/* 6712 */     beginTrackingImap();
/*      */     
/* 6714 */     for (int id : itemIds) {
/* 6715 */       if (id <= 0) {
/* 6716 */         throw MailItem.noSuchItem(id, type);
/*      */       }
/*      */     }
/*      */     
/* 6720 */     ImapCopyItem redoRecorder = new ImapCopyItem(this.mId, type, folderId);
/*      */     
/* 6722 */     boolean success = false;
/*      */     try {
/* 6724 */       beginTransaction("icopy", octxt, redoRecorder);
/* 6725 */       ImapCopyItem redoPlayer = (ImapCopyItem)currentChange().getRedoPlayer();
/*      */       
/* 6727 */       Folder target = getFolderById(folderId);
/*      */       
/*      */ 
/* 6730 */       MailItem[] items = getItemById(itemIds, type);
/* 6731 */       for (MailItem item : items) {
/* 6732 */         checkItemChangeID(item);
/*      */       }
/* 6734 */       List<MailItem> result = new ArrayList();
/*      */       
/* 6736 */       for (MailItem item : items) {
/* 6737 */         int srcId = item.getId();
/* 6738 */         int newId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getDestId(srcId));
/* 6739 */         String newUuid = redoPlayer == null ? UUIDUtil.generateUUID() : redoPlayer.getDestUuid(srcId);
/*      */         
/* 6741 */         trainSpamFilter(octxt, item, target, "imap copy");
/*      */         
/* 6743 */         MailItem copy = item.icopy(target, newId, newUuid);
/* 6744 */         result.add(copy);
/* 6745 */         redoRecorder.setDest(srcId, newId, newUuid);
/*      */       }
/*      */       
/* 6748 */       success = true;
/* 6749 */       return result;
/*      */     } finally {
/* 6751 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private <T extends MailItem> T trainSpamFilter(OperationContext octxt, T item, Folder target, String opDescription) {
/* 6756 */     if (currentChange().getRedoPlayer() != null)
/*      */     {
/* 6758 */       return item;
/*      */     }
/* 6760 */     MailItem.TargetConstraint tcon = getOperationTargetConstraint();
/*      */     try
/*      */     {
/* 6763 */       List<? extends MailItem> items = (item instanceof Conversation) ? ((Conversation)item).getMessages() : Arrays.asList(new MailItem[] { item });
/*      */       
/* 6765 */       trashAliases = getTrashAliases(octxt);
/* 6766 */       for (MailItem candidate : items)
/*      */       {
/*      */ 
/* 6769 */         boolean fromSpam = candidate.inSpam();
/* 6770 */         boolean toSpam = target.inSpam();
/* 6771 */         if (((fromSpam) || (toSpam)) && 
/*      */         
/*      */ 
/* 6774 */           ((!fromSpam) || ((!toSpam) && (!target.inTrash()) && (!inFolder(trashAliases, target)))) && 
/*      */           
/*      */ 
/* 6777 */           (MailItem.TargetConstraint.checkItem(tcon, item)) && (item.canAccess((short)1)))
/*      */         {
/*      */           try
/*      */           {
/* 6781 */             SpamHandler.SpamReport report = new SpamHandler.SpamReport(toSpam, opDescription, target.getPath());
/* 6782 */             Folder source = item.getFolder();
/* 6783 */             if (!source.equals(target)) {
/* 6784 */               report.setSourceFolderPath(source.getPath());
/*      */             }
/* 6786 */             SpamHandler.getInstance().handle(octxt, this, candidate.getId(), candidate.getType(), report);
/*      */           } catch (Exception e) {
/* 6788 */             ZimbraLog.mailop.info("could not train spam filter: " + MailItem.getMailopContext(candidate), e);
/*      */           } }
/*      */       }
/*      */     } catch (ServiceException e) { List<Folder> trashAliases;
/* 6792 */       ZimbraLog.mailop.info("could not train spam filter: " + MailItem.getMailopContext(item), e);
/*      */     }
/*      */     
/* 6795 */     return item;
/*      */   }
/*      */   
/*      */   private List<Folder> getTrashAliases(OperationContext octx) throws ServiceException {
/* 6799 */     String[] aliases = Provisioning.getInstance().getConfig().getSpamTrashAlias();
/* 6800 */     List<Folder> result = new ArrayList(aliases.length);
/* 6801 */     for (String path : aliases) {
/*      */       try {
/* 6803 */         result.add(getFolderByPath(octx, path));
/*      */       }
/*      */       catch (ServiceException ignore) {}
/*      */     }
/* 6807 */     return result;
/*      */   }
/*      */   
/*      */   private boolean inFolder(List<Folder> base, Folder target) throws ServiceException {
/* 6811 */     for (Folder folder : base) {
/* 6812 */       if ((folder.getId() == target.getId()) || (folder.isDescendant(target))) {
/* 6813 */         return true;
/*      */       }
/*      */     }
/* 6816 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void move(OperationContext octxt, int itemId, MailItem.Type type, int targetId)
/*      */     throws ServiceException
/*      */   {
/* 6831 */     move(octxt, new int[] { itemId }, type, targetId, null);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void move(OperationContext octxt, int itemId, MailItem.Type type, int targetId, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6848 */     move(octxt, new int[] { itemId }, type, targetId, tcon);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void move(OperationContext octxt, int[] itemIds, MailItem.Type type, int targetId, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6865 */     this.lock.lock();
/*      */     try
/*      */     {
/* 6868 */       moveInternal(octxt, itemIds, type, targetId, tcon);
/*      */     }
/*      */     catch (ServiceException e)
/*      */     {
/* 6872 */       if ((!e.getCode().equals("mail.ALREADY_EXISTS")) || (targetId != 3)) {
/* 6873 */         throw e;
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 6878 */       if (itemIds.length == 1)
/*      */       {
/* 6880 */         rename(octxt, itemIds[0], type, generateAlternativeItemName(octxt, itemIds[0], type), targetId);
/*      */       }
/*      */       else {
/* 6883 */         for (int id : itemIds)
/*      */         {
/*      */           try
/*      */           {
/* 6887 */             moveInternal(octxt, new int[] { id }, type, targetId, tcon);
/*      */           }
/*      */           catch (ServiceException e) {
/* 6890 */             rename(octxt, id, type, generateAlternativeItemName(octxt, id, type), targetId);
/*      */           }
/*      */         }
/*      */       }
/*      */     } finally {
/* 6895 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */   private String generateAlternativeItemName(OperationContext octxt, int id, MailItem.Type type) throws ServiceException
/*      */   {
/* 6901 */     String name = getItemById(octxt, id, type).getName();
/* 6902 */     String uuid = '{' + UUID.randomUUID().toString() + '}';
/* 6903 */     if (name.length() + uuid.length() > 255) {
/* 6904 */       return name.substring(0, 255 - uuid.length()) + uuid;
/*      */     }
/* 6906 */     return name + uuid;
/*      */   }
/*      */   
/*      */ 
/*      */   private void moveInternal(OperationContext octxt, int[] itemIds, MailItem.Type type, int targetId, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 6913 */     MoveItem redoRecorder = new MoveItem(this.mId, itemIds, type, targetId, tcon);
/*      */     
/* 6915 */     boolean success = false;
/*      */     try {
/* 6917 */       beginTransaction("move", octxt, redoRecorder);
/* 6918 */       setOperationTargetConstraint(tcon);
/*      */       
/* 6920 */       Folder target = getFolderById(targetId);
/*      */       
/* 6922 */       MailItem[] items = getItemById(itemIds, type);
/* 6923 */       for (MailItem item : items) {
/* 6924 */         checkItemChangeID(item);
/*      */       }
/* 6926 */       int oldUIDNEXT = target.getImapUIDNEXT();
/* 6927 */       boolean resetUIDNEXT = false;
/*      */       
/* 6929 */       for (MailItem item : items)
/*      */       {
/*      */ 
/* 6932 */         trainSpamFilter(octxt, item, target, "move");
/*      */         
/*      */ 
/* 6935 */         boolean moved = item.move(target);
/*      */         
/*      */ 
/* 6938 */         if ((moved) && (!resetUIDNEXT) && (isTrackingImap()) && (((item instanceof Conversation)) || ((item instanceof Message)) || ((item instanceof Contact))))
/*      */         {
/* 6940 */           resetUIDNEXT = true;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 6945 */       if ((resetUIDNEXT) && (oldUIDNEXT == target.getImapUIDNEXT())) {
/* 6946 */         MoveItem redoPlayer = (MoveItem)currentChange().getRedoPlayer();
/* 6947 */         redoRecorder.setUIDNEXT(getNextItemId(redoPlayer == null ? -1 : redoPlayer.getUIDNEXT()));
/* 6948 */         target.updateUIDNEXT();
/*      */       }
/* 6950 */       success = true;
/*      */     } finally {
/* 6952 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void rename(OperationContext octxt, int id, MailItem.Type type, String name, int folderId) throws ServiceException
/*      */   {
/* 6958 */     rename(octxt, id, type, name, folderId, null);
/*      */   }
/*      */   
/*      */   public void rename(OperationContext octxt, int id, MailItem.Type type, String name, int folderId, Long date) throws ServiceException
/*      */   {
/* 6963 */     if ((name != null) && (name.startsWith("/"))) {
/* 6964 */       rename(octxt, id, type, name);
/* 6965 */       return;
/*      */     }
/*      */     
/* 6968 */     name = StringUtil.stripControlCharacters(name);
/* 6969 */     if (Strings.isNullOrEmpty(name)) {
/* 6970 */       throw ServiceException.INVALID_REQUEST("cannot set name to empty string", null);
/*      */     }
/*      */     
/* 6973 */     RenameItem redoRecorder = new RenameItem(this.mId, id, type, name, folderId, date);
/*      */     
/* 6975 */     boolean success = false;
/*      */     try {
/* 6977 */       beginTransaction("rename", octxt, redoRecorder);
/*      */       
/* 6979 */       MailItem item = getItemById(id, type);
/* 6980 */       checkItemChangeID(item);
/* 6981 */       if (folderId <= 0) {
/* 6982 */         folderId = item.getFolderId();
/*      */       }
/* 6984 */       Folder target = getFolderById(folderId);
/* 6985 */       trainSpamFilter(octxt, item, target, "rename");
/*      */       
/* 6987 */       String oldName = item.getName();
/* 6988 */       item.rename(name, target);
/*      */       
/* 6990 */       if (date != null) {
/* 6991 */         item.setDate(date.longValue());
/*      */       }
/*      */       
/* 6994 */       if ((item instanceof Tag)) {
/* 6995 */         this.mTagCache.remove(oldName.toLowerCase());
/* 6996 */         this.mTagCache.put(name.toLowerCase(), (Tag)item);
/*      */       }
/* 6998 */       success = true;
/*      */     } finally {
/* 7000 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void rename(OperationContext octxt, int id, MailItem.Type type, String path) throws ServiceException {
/* 7005 */     if ((path == null) || (!path.startsWith("/"))) {
/* 7006 */       rename(octxt, id, type, path, -1);
/* 7007 */       return;
/*      */     }
/*      */     
/* 7010 */     RenameItemPath redoRecorder = new RenameItemPath(this.mId, id, type, path);
/*      */     
/* 7012 */     boolean success = false;
/*      */     try {
/* 7014 */       beginTransaction("renameFolderPath", octxt, redoRecorder);
/* 7015 */       RenameItemPath redoPlayer = (RenameItemPath)currentChange().getRedoPlayer();
/*      */       
/* 7017 */       MailItem item = getItemById(id, type);
/*      */       
/* 7019 */       checkItemChangeID(item);
/*      */       
/* 7021 */       String[] parts = path.substring(1).split("/");
/* 7022 */       if (parts.length == 0) {
/* 7023 */         throw MailServiceException.ALREADY_EXISTS(path);
/*      */       }
/* 7025 */       int[] recorderParentIds = new int[parts.length - 1];
/* 7026 */       String[] recorderParentUuids = new String[parts.length - 1];
/* 7027 */       int[] playerParentIds = redoPlayer == null ? null : redoPlayer.getParentIds();
/* 7028 */       String[] playerParentUuids = redoPlayer == null ? null : redoPlayer.getParentUuids();
/* 7029 */       if ((playerParentIds != null) && (playerParentIds.length != recorderParentIds.length)) {
/* 7030 */         throw ServiceException.FAILURE("incorrect number of path segment ids in redo player", null);
/*      */       }
/* 7032 */       if ((playerParentUuids != null) && (playerParentUuids.length != recorderParentUuids.length)) {
/* 7033 */         throw ServiceException.FAILURE("incorrect number of path segment uuids in redo player", null);
/*      */       }
/* 7035 */       Folder parent = getFolderById(1);
/* 7036 */       for (int i = 0; i < parts.length - 1; i++) {
/* 7037 */         String name = MailItem.validateItemName(parts[i]);
/* 7038 */         int subfolderId = playerParentIds == null ? -1 : playerParentIds[i];
/* 7039 */         String subfolderUuid = playerParentUuids == null ? UUIDUtil.generateUUID() : playerParentUuids[i];
/* 7040 */         Folder subfolder = parent.findSubfolder(name);
/* 7041 */         if (subfolder == null) {
/* 7042 */           subfolder = Folder.create(getNextItemId(subfolderId), subfolderUuid, this, parent, name, (byte)0, MailItem.Type.UNKNOWN, 0, null, null, null, null);
/* 7043 */         } else { if ((subfolderId != -1) && (subfolderId != subfolder.getId()))
/* 7044 */             throw ServiceException.FAILURE("parent folder id changed since operation was recorded", null);
/* 7045 */           if ((!subfolder.getName().equals(name)) && (subfolder.isMutable()))
/*      */           {
/* 7047 */             subfolder.rename(name, parent); }
/*      */         }
/* 7049 */         recorderParentIds[i] = subfolder.getId();
/* 7050 */         recorderParentUuids[i] = subfolder.getUuid();
/* 7051 */         parent = subfolder;
/*      */       }
/* 7053 */       redoRecorder.setParentIdsAndUuids(recorderParentIds, recorderParentUuids);
/*      */       
/* 7055 */       trainSpamFilter(octxt, item, parent, "rename");
/*      */       
/* 7057 */       String name = parts[(parts.length - 1)];
/* 7058 */       item.rename(name, parent);
/*      */       
/* 7060 */       success = true;
/*      */     } finally {
/* 7062 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public void delete(OperationContext octxt, int itemId, MailItem.Type type)
/*      */     throws ServiceException
/*      */   {
/* 7071 */     delete(octxt, new int[] { itemId }, type, null);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void delete(OperationContext octxt, int itemId, MailItem.Type type, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 7085 */     delete(octxt, new int[] { itemId }, type, tcon);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void delete(OperationContext octxt, int[] itemIds, MailItem.Type type, MailItem.TargetConstraint tcon, boolean useEmptyForFolders, List<Integer> nonExistingItems)
/*      */     throws ServiceException
/*      */   {
/* 7102 */     DeleteItem redoRecorder = new DeleteItem(this.mId, itemIds, type, tcon);
/*      */     
/* 7104 */     List<Integer> folderIds = Lists.newArrayList();
/* 7105 */     boolean success = false;
/*      */     try {
/* 7107 */       beginTransaction("delete", octxt, redoRecorder);
/* 7108 */       setOperationTargetConstraint(tcon);
/*      */       
/* 7110 */       for (int id : itemIds) {
/* 7111 */         if (id != -1)
/*      */         {
/*      */           MailItem item;
/*      */           try
/*      */           {
/* 7116 */             item = getItemById(id, MailItem.Type.UNKNOWN);
/*      */           } catch (MailServiceException.NoSuchItemException nsie) {
/* 7118 */             if (nonExistingItems != null) {
/* 7119 */               nonExistingItems.add(Integer.valueOf(id));
/*      */             }
/*      */             
/* 7122 */             continue;
/*      */           }
/*      */           
/*      */ 
/* 7126 */           if (!MailItem.isAcceptableType(type, item.getType()))
/* 7127 */             throw MailItem.noSuchItem(id, type);
/* 7128 */           if ((!checkItemChangeID(item)) && ((item instanceof Tag))) {
/* 7129 */             throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */           }
/* 7131 */           if ((useEmptyForFolders) && (MailItem.Type.FOLDER.equals(item.getType()))) {
/* 7132 */             folderIds.add(Integer.valueOf(id));
/*      */           }
/*      */           else {
/* 7135 */             item.delete(false);
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 7140 */       TypedIdList tombstones = collectPendingTombstones();
/* 7141 */       if ((tombstones != null) && (!tombstones.isEmpty())) {
/* 7142 */         DbMailItem.writeTombstones(this, tombstones);
/*      */       }
/*      */       
/* 7145 */       success = true;
/*      */     } finally {
/* 7147 */       endTransaction(success);
/*      */     }
/* 7149 */     for (Integer folderId : folderIds) {
/* 7150 */       emptyFolder(octxt, folderId.intValue(), true, true, tcon);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void delete(OperationContext octxt, int[] itemIds, MailItem.Type type, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 7165 */     delete(octxt, itemIds, type, tcon, true, null);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void delete(OperationContext octxt, int[] itemIds, MailItem.Type type, MailItem.TargetConstraint tcon, List<Integer> nonExistingItems)
/*      */     throws ServiceException
/*      */   {
/* 7180 */     delete(octxt, itemIds, type, tcon, true, nonExistingItems);
/*      */   }
/*      */   
/*      */   TypedIdList collectPendingTombstones() {
/* 7184 */     if ((!isTrackingSync()) || (currentChange().deletes == null)) {
/* 7185 */       return null;
/*      */     }
/* 7187 */     return new TypedIdList(currentChange().deletes.itemIds);
/*      */   }
/*      */   
/*      */   private int deleteFromDumpster(int[] itemIds) throws ServiceException {
/* 7191 */     Folder trash = getFolderById(3);
/* 7192 */     if (!trash.canAccess((short)8)) {
/* 7193 */       throw ServiceException.PERM_DENIED("dumpster access denied");
/*      */     }
/*      */     
/* 7196 */     int numDeleted = 0;
/* 7197 */     for (int id : itemIds) {
/* 7198 */       MailItem item = null;
/*      */       try {
/* 7200 */         item = getItemById(id, MailItem.Type.UNKNOWN, true);
/*      */       } catch (MailServiceException.NoSuchItemException e) {
/* 7202 */         ZimbraLog.mailbox.info("ignoring NO_SUCH_ITEM exception during dumpster delete; item id=" + id);
/* 7203 */         continue;
/*      */       }
/* 7205 */       item.delete();
/* 7206 */       numDeleted++;
/*      */     }
/* 7208 */     return numDeleted;
/*      */   }
/*      */   
/*      */   public int deleteFromDumpster(OperationContext octxt, int[] itemIds) throws ServiceException {
/* 7212 */     boolean isRedo = (octxt != null) && (octxt.isRedo());
/* 7213 */     if ((!isRedo) && (!hasFullAdminAccess(octxt))) {
/* 7214 */       throw ServiceException.PERM_DENIED("only admins can delete from dumpster");
/*      */     }
/* 7216 */     DeleteItemFromDumpster redoRecorder = new DeleteItemFromDumpster(this.mId, itemIds);
/* 7217 */     boolean success = false;
/*      */     try {
/* 7219 */       beginTransaction("deleteFromDumpster[]", octxt, redoRecorder);
/* 7220 */       int numDeleted = deleteFromDumpster(itemIds);
/* 7221 */       success = true;
/* 7222 */       return numDeleted;
/*      */     } finally {
/* 7224 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public int emptyDumpster(OperationContext octxt) throws ServiceException {
/* 7229 */     if (!hasFullAdminAccess(octxt)) {
/* 7230 */       throw ServiceException.PERM_DENIED("only admins can delete from dumpster");
/*      */     }
/*      */     
/* 7233 */     int numDeleted = 0;
/* 7234 */     int batchSize = Provisioning.getInstance().getLocalServer().getMailEmptyFolderBatchSize();
/* 7235 */     ZimbraLog.mailbox.info("Emptying dumpster with batchSize=" + batchSize);
/* 7236 */     DbMailItem.QueryParams params = new DbMailItem.QueryParams();
/*      */     
/* 7238 */     params.setChangeDateBefore(Integer.valueOf((int)(System.currentTimeMillis() / 1000L + 1L))).setRowLimit(Integer.valueOf(batchSize));
/*      */     for (;;) {
/* 7240 */       this.lock.lock();
/*      */       try {
/* 7242 */         Set<Integer> itemIds = null;
/*      */         
/* 7244 */         DbPool.DbConnection conn = DbPool.getConnection(this);
/*      */         try {
/* 7246 */           itemIds = DbMailItem.getIds(this, conn, params, true);
/*      */         } finally {
/* 7248 */           conn.closeQuietly();
/*      */         }
/*      */         
/* 7251 */         if (itemIds.isEmpty())
/*      */         {
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 7257 */           this.lock.release(); break;
/*      */         }
/* 7255 */         numDeleted += deleteFromDumpster(octxt, ArrayUtil.toIntArray(itemIds));
/*      */       } finally {
/* 7257 */         this.lock.release();
/*      */       }
/*      */     }
/* 7260 */     return numDeleted;
/*      */   }
/*      */   
/*      */   private int purgeDumpster(long olderThanMillis, int maxItems) throws ServiceException {
/* 7264 */     DbMailItem.QueryParams params = new DbMailItem.QueryParams();
/* 7265 */     params.setChangeDateBefore(Integer.valueOf((int)(olderThanMillis / 1000L))).setRowLimit(Integer.valueOf(maxItems));
/*      */     
/* 7267 */     Set<Integer> itemIds = DbMailItem.getIds(this, getOperationConnection(), params, true);
/* 7268 */     if (!itemIds.isEmpty()) {
/* 7269 */       return deleteFromDumpster(ArrayUtil.toIntArray(itemIds));
/*      */     }
/* 7271 */     return 0;
/*      */   }
/*      */   
/*      */   public Tag createTag(OperationContext octxt, String name, byte color) throws ServiceException
/*      */   {
/* 7276 */     return createTag(octxt, name, new Color(color));
/*      */   }
/*      */   
/*      */   public Tag createTag(OperationContext octxt, String name, Color color) throws ServiceException {
/* 7280 */     name = StringUtil.stripControlCharacters(name);
/* 7281 */     if (Strings.isNullOrEmpty(name)) {
/* 7282 */       throw ServiceException.INVALID_REQUEST("tag must have a name", null);
/*      */     }
/* 7284 */     CreateTag redoRecorder = new CreateTag(this.mId, name, color);
/*      */     
/* 7286 */     boolean success = false;
/*      */     try {
/* 7288 */       beginTransaction("createTag", octxt, redoRecorder);
/* 7289 */       if (!hasFullAccess()) {
/* 7290 */         throw ServiceException.PERM_DENIED("you do not have sufficient permissions");
/*      */       }
/*      */       
/* 7293 */       CreateTag redoPlayer = (CreateTag)currentChange().getRedoPlayer();
/* 7294 */       int tagId = redoPlayer == null ? -1 : redoPlayer.getTagId();
/* 7295 */       Tag tag = createTagInternal(tagId, name, color, true);
/* 7296 */       redoRecorder.setTagId(tag.getId());
/* 7297 */       success = true;
/* 7298 */       return tag;
/*      */     } finally {
/* 7300 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   Tag createTagInternal(int tagId, String name, Color color, boolean listed) throws ServiceException {
/*      */     try {
/* 7306 */       Tag tag = getTagByName(name);
/* 7307 */       if (!listed)
/*      */       {
/* 7309 */         return tag; }
/* 7310 */       if (tag.isListed())
/*      */       {
/* 7312 */         throw MailServiceException.ALREADY_EXISTS(name);
/*      */       }
/*      */       
/*      */ 
/* 7316 */       markItemCreated(tag);
/* 7317 */       tag.setListed();
/* 7318 */       if (!name.equals(tag.getName())) {
/* 7319 */         tag.rename(name);
/*      */       }
/* 7321 */       tag.setColor(color);
/* 7322 */       return tag;
/*      */     }
/*      */     catch (MailServiceException.NoSuchItemException nsie) {}
/* 7325 */     return Tag.create(this, getNextItemId(tagId), name, color, listed);
/*      */   }
/*      */   
/*      */   public Note createNote(OperationContext octxt, String content, Note.Rectangle location, byte color, int folderId)
/*      */     throws ServiceException
/*      */   {
/* 7331 */     return createNote(octxt, content, location, new Color(color), folderId);
/*      */   }
/*      */   
/*      */   public Note createNote(OperationContext octxt, String content, Note.Rectangle location, Color color, int folderId) throws ServiceException
/*      */   {
/* 7336 */     content = StringUtil.stripControlCharacters(content);
/* 7337 */     if (Strings.isNullOrEmpty(content)) {
/* 7338 */       throw ServiceException.INVALID_REQUEST("note content may not be empty", null);
/*      */     }
/* 7340 */     CreateNote redoRecorder = new CreateNote(this.mId, folderId, content, color, location);
/*      */     
/* 7342 */     boolean success = false;
/*      */     try {
/* 7344 */       beginTransaction("createNote", octxt, redoRecorder);
/* 7345 */       CreateNote redoPlayer = (CreateNote)currentChange().getRedoPlayer();
/*      */       
/* 7347 */       int noteId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getNoteId());
/* 7348 */       Note note = Note.create(noteId, getFolderById(folderId), content, location, color, null);
/* 7349 */       redoRecorder.setNoteId(noteId);
/*      */       
/* 7351 */       this.index.add(note);
/* 7352 */       success = true;
/* 7353 */       return note;
/*      */     } finally {
/* 7355 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void editNote(OperationContext octxt, int noteId, String content) throws ServiceException {
/* 7360 */     content = StringUtil.stripControlCharacters(content);
/* 7361 */     if (Strings.isNullOrEmpty(content)) {
/* 7362 */       throw ServiceException.INVALID_REQUEST("note content may not be empty", null);
/*      */     }
/* 7364 */     EditNote redoRecorder = new EditNote(this.mId, noteId, content);
/*      */     
/* 7366 */     boolean success = false;
/*      */     try {
/* 7368 */       beginTransaction("editNote", octxt, redoRecorder);
/*      */       
/* 7370 */       Note note = getNoteById(noteId);
/* 7371 */       checkItemChangeID(note);
/*      */       
/* 7373 */       note.setContent(content);
/* 7374 */       this.index.add(note);
/*      */       
/* 7376 */       success = true;
/*      */     } finally {
/* 7378 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void repositionNote(OperationContext octxt, int noteId, Note.Rectangle location) throws ServiceException {
/* 7383 */     Preconditions.checkNotNull(location, "must specify note bounds");
/* 7384 */     RepositionNote redoRecorder = new RepositionNote(this.mId, noteId, location);
/*      */     
/* 7386 */     boolean success = false;
/*      */     try {
/* 7388 */       beginTransaction("repositionNote", octxt, redoRecorder);
/*      */       
/* 7390 */       Note note = getNoteById(noteId);
/* 7391 */       checkItemChangeID(note);
/*      */       
/* 7393 */       note.reposition(location);
/* 7394 */       success = true;
/*      */     } finally {
/* 7396 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   CalendarItem createCalendarItem(int folderId, int flags, Tag.NormalizedTags ntags, String uid, ParsedMessage pm, Invite invite, MailItem.CustomMetadata custom)
/*      */     throws ServiceException
/*      */   {
/* 7404 */     CreateCalendarItemPlayer redoPlayer = (CreateCalendarItemPlayer)currentChange().getRedoPlayer();
/* 7405 */     CreateCalendarItemRecorder redoRecorder = (CreateCalendarItemRecorder)currentChange().getRedoRecorder();
/*      */     
/* 7407 */     int newCalItemId = redoPlayer == null ? -1 : redoPlayer.getCalendarItemId();
/* 7408 */     int createId = getNextItemId(newCalItemId);
/*      */     
/* 7410 */     CalendarItem calItem = CalendarItem.create(createId, getFolderById(folderId), flags, ntags, uid, pm, invite, -2L, custom);
/*      */     
/*      */ 
/* 7413 */     if (redoRecorder != null) {
/* 7414 */       redoRecorder.setCalendarItemAttrs(calItem.getId(), calItem.getFolderId());
/*      */     }
/* 7416 */     return calItem;
/*      */   }
/*      */   
/*      */   public Contact createContact(OperationContext octxt, ParsedContact pc, int folderId, String[] tags) throws ServiceException
/*      */   {
/* 7421 */     StoreManager sm = StoreManager.getInstance();
/* 7422 */     StagedBlob staged = null;
/* 7423 */     if (pc.hasAttachment())
/*      */     {
/* 7425 */       InputStream is = null;
/*      */       try {
/* 7427 */         staged = sm.stage(is = pc.getContentStream(), (int)pc.getSize(), this);
/*      */       } catch (IOException ioe) {
/* 7429 */         throw ServiceException.FAILURE("could not save contact blob", ioe);
/*      */       } finally {
/* 7431 */         ByteUtil.closeStream(is);
/*      */       }
/*      */     }
/*      */     
/* 7435 */     CreateContact redoRecorder = new CreateContact(this.mId, folderId, pc, tags);
/*      */     
/* 7437 */     boolean success = false;
/*      */     try {
/* 7439 */       beginTransaction("createContact", octxt, redoRecorder);
/* 7440 */       CreateContact redoPlayer = (CreateContact)currentChange().getRedoPlayer();
/* 7441 */       boolean isRedo = redoPlayer != null;
/*      */       
/* 7443 */       Tag.NormalizedTags ntags = new Tag.NormalizedTags(this, tags);
/*      */       
/* 7445 */       int contactId = getNextItemId(isRedo ? redoPlayer.getContactId() : -1);
/*      */       
/* 7447 */       MailboxBlob mblob = null;
/* 7448 */       if (pc.hasAttachment()) {
/*      */         try {
/* 7450 */           mblob = sm.renameTo(staged, this, contactId, getOperationChangeID());
/* 7451 */           markOtherItemDirty(mblob);
/*      */         } catch (IOException ioe) {
/* 7453 */           throw ServiceException.FAILURE("could not save contact blob", ioe);
/*      */         }
/*      */       }
/*      */       
/* 7457 */       int flags = 0;
/* 7458 */       Contact con = Contact.create(contactId, getFolderById(folderId), mblob, pc, flags, ntags, null);
/* 7459 */       redoRecorder.setContactId(contactId);
/*      */       
/* 7461 */       this.index.add(con);
/*      */       
/* 7463 */       success = true;
/* 7464 */       return con;
/*      */     } finally {
/* 7466 */       endTransaction(success);
/* 7467 */       sm.quietDelete(staged);
/*      */     }
/*      */   }
/*      */   
/*      */   public void modifyContact(OperationContext octxt, int contactId, ParsedContact pc) throws ServiceException {
/* 7472 */     StoreManager sm = StoreManager.getInstance();
/* 7473 */     StagedBlob staged = null;
/* 7474 */     if (pc.hasAttachment())
/*      */     {
/* 7476 */       InputStream is = null;
/*      */       try {
/* 7478 */         staged = sm.stage(is = pc.getContentStream(), pc.getSize(), this);
/*      */       } catch (IOException ioe) {
/* 7480 */         throw ServiceException.FAILURE("could not save contact blob", ioe);
/*      */       } finally {
/* 7482 */         ByteUtil.closeStream(is);
/*      */       }
/*      */     }
/*      */     
/* 7486 */     ModifyContact redoRecorder = new ModifyContact(this.mId, contactId, pc);
/* 7487 */     boolean success = false;
/*      */     try {
/* 7489 */       beginTransaction("modifyContact", octxt, redoRecorder);
/* 7490 */       Contact con = getContactById(contactId);
/* 7491 */       if (!checkItemChangeID(con)) {
/* 7492 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/*      */       
/*      */       try
/*      */       {
/* 7497 */         con.setContent(staged, pc);
/*      */       } catch (IOException ioe) {
/* 7499 */         throw ServiceException.FAILURE("could not save contact blob", ioe);
/*      */       }
/*      */       
/* 7502 */       this.index.add(con);
/* 7503 */       success = true;
/*      */     } finally {
/* 7505 */       endTransaction(success);
/* 7506 */       sm.quietDelete(staged);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public List<Contact> createAutoContact(OperationContext octxt, Collection<com.zimbra.common.mime.InternetAddress> addrs)
/*      */     throws IOException
/*      */   {
/* 7520 */     if (addrs.isEmpty()) {
/* 7521 */       return Collections.emptyList();
/*      */     }
/* 7523 */     List<Contact> result = new ArrayList(addrs.size());
/* 7524 */     String locale = (octxt != null) && (octxt.getAuthenticatedUser() != null) ? octxt.getAuthenticatedUser().getPrefLocale() : null;
/* 7525 */     boolean nameFormatLastFirst = false;
/* 7526 */     if ((locale != null) && (locale.equals("ja"))) {
/* 7527 */       nameFormatLastFirst = true;
/*      */     }
/* 7529 */     for (com.zimbra.common.mime.InternetAddress addr : addrs) {
/* 7530 */       ZimbraLog.mailbox.debug("Auto-adding new contact addr=%s", new Object[] { addr });
/*      */       try {
/* 7532 */         result.add(createContact(octxt, new ParsedContact(new ParsedAddress(addr, nameFormatLastFirst).getAttributes()), 13, null));
/*      */       }
/*      */       catch (ServiceException e) {
/* 7535 */         if (e.getCode().equals("mail.TOO_MANY_CONTACTS")) {
/* 7536 */           ZimbraLog.mailbox.warn("Aborting contact addition, Failed to auto-add contact addr=%s", addr, e);
/*      */           
/* 7538 */           return result;
/*      */         }
/* 7540 */         ZimbraLog.mailbox.warn("Failed to auto-add contact addr=%s", addr, e);
/*      */       }
/*      */     }
/* 7543 */     return result;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Collection<Address> newContactAddrs(Collection<Address> addrs)
/*      */     throws IOException
/*      */   {
/* 7553 */     if (addrs.isEmpty()) {
/* 7554 */       return Collections.emptySet();
/*      */     }
/* 7556 */     if (this.lock.isWriteLockedByCurrentThread()) {
/* 7557 */       ZimbraLog.mailbox.warn("Unable to auto-add contact while holding Mailbox lock");
/* 7558 */       return Collections.emptySet();
/*      */     }
/* 7560 */     Set<Address> newAddrs = new HashSet();
/* 7561 */     for (Address addr : addrs) {
/* 7562 */       if ((addr instanceof javax.mail.internet.InternetAddress)) {
/* 7563 */         javax.mail.internet.InternetAddress iaddr = (javax.mail.internet.InternetAddress)addr;
/* 7564 */         if ((!Strings.isNullOrEmpty(iaddr.getAddress())) && (!this.index.existsInContacts(Collections.singleton(new com.zimbra.common.mime.InternetAddress(iaddr.getPersonal(), iaddr.getAddress())))))
/*      */         {
/*      */ 
/* 7567 */           newAddrs.add(addr);
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 7572 */     return newAddrs;
/*      */   }
/*      */   
/*      */   @Deprecated
/*      */   public Folder createFolder(OperationContext octxt, String name, int parentId, MailItem.Type defaultView, int flags, byte color, String url)
/*      */     throws ServiceException
/*      */   {
/* 7579 */     return createFolder(octxt, name, parentId, (byte)0, defaultView, flags, color, url);
/*      */   }
/*      */   
/*      */   @Deprecated
/*      */   public Folder createFolder(OperationContext octxt, String name, int parentId, byte attrs, MailItem.Type defaultView, int flags, byte color, String url)
/*      */     throws ServiceException
/*      */   {
/* 7586 */     return createFolder(octxt, name, parentId, attrs, defaultView, flags, new Color(color), url);
/*      */   }
/*      */   
/*      */   @Deprecated
/*      */   public Folder createFolder(OperationContext octxt, String name, int parentId, byte attrs, MailItem.Type defaultView, int flags, Color color, String url)
/*      */     throws ServiceException
/*      */   {
/* 7593 */     Folder.FolderOptions fopt = new Folder.FolderOptions();
/* 7594 */     fopt.setAttributes(attrs).setDefaultView(defaultView).setFlags(flags).setColor(color).setUrl(url);
/* 7595 */     return createFolder(octxt, name, parentId, fopt);
/*      */   }
/*      */   
/*      */   public Folder createFolder(OperationContext octxt, String name, int parentId, Folder.FolderOptions fopt) throws ServiceException
/*      */   {
/* 7600 */     CreateFolder redoRecorder = new CreateFolder(this.mId, name, parentId, fopt);
/*      */     
/* 7602 */     boolean success = false;
/*      */     try {
/* 7604 */       beginTransaction("createFolder", octxt, redoRecorder);
/* 7605 */       CreateFolder redoPlayer = (CreateFolder)currentChange().getRedoPlayer();
/*      */       String uuid;
/*      */       int folderId;
/*      */       String uuid;
/* 7609 */       if (redoPlayer == null) {
/* 7610 */         int folderId = getNextItemId(-1);
/* 7611 */         uuid = Strings.emptyToNull(fopt.getUuid()) == null ? UUIDUtil.generateUUID() : fopt.getUuid();
/*      */       } else {
/* 7613 */         folderId = getNextItemId(redoPlayer.getFolderId());
/* 7614 */         uuid = redoPlayer.getFolderUuid();
/*      */       }
/*      */       
/* 7617 */       Folder folder = Folder.create(folderId, uuid, this, getFolderById(parentId), name, fopt.getAttributes(), fopt.getDefaultView(), fopt.getFlags(), fopt.getColor(), fopt.getDate(), fopt.getUrl(), fopt.getCustomMetadata());
/*      */       
/*      */ 
/* 7620 */       redoRecorder.setFolderIdAndUuid(folder.getId(), folder.getUuid());
/* 7621 */       success = true;
/* 7622 */       updateRssDataSource(folder);
/* 7623 */       return folder;
/*      */     } finally {
/* 7625 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Folder createFolder(OperationContext octxt, String path, Folder.FolderOptions fopt)
/*      */     throws ServiceException
/*      */   {
/* 7648 */     if (path == null) {
/* 7649 */       throw ServiceException.FAILURE("null path passed to Mailbox.createFolderPath", null);
/*      */     }
/* 7651 */     if (!path.startsWith("/")) {
/* 7652 */       path = '/' + path;
/*      */     }
/* 7654 */     if ((path.endsWith("/")) && (path.length() > 1)) {
/* 7655 */       path = path.substring(0, path.length() - 1);
/*      */     }
/* 7657 */     CreateFolderPath redoRecorder = new CreateFolderPath(this.mId, path, fopt);
/*      */     
/* 7659 */     boolean success = false;
/*      */     try {
/* 7661 */       beginTransaction("createFolderPath", octxt, redoRecorder);
/* 7662 */       CreateFolderPath redoPlayer = (CreateFolderPath)currentChange().getRedoPlayer();
/*      */       
/* 7664 */       String[] parts = path.substring(1).split("/");
/* 7665 */       if (parts.length == 0) {
/* 7666 */         throw MailServiceException.ALREADY_EXISTS(path);
/*      */       }
/*      */       
/* 7669 */       int[] recorderFolderIds = new int[parts.length];
/* 7670 */       String[] recorderFolderUuids = new String[parts.length];
/* 7671 */       int[] playerFolderIds = redoPlayer == null ? null : redoPlayer.getFolderIds();
/* 7672 */       String[] playerFolderUuids = redoPlayer == null ? null : redoPlayer.getFolderUuids();
/* 7673 */       if ((playerFolderIds != null) && (playerFolderIds.length != recorderFolderIds.length)) {
/* 7674 */         throw ServiceException.FAILURE("incorrect number of path segment ids in redo player", null);
/*      */       }
/* 7676 */       if ((playerFolderUuids != null) && (playerFolderUuids.length != recorderFolderUuids.length)) {
/* 7677 */         throw ServiceException.FAILURE("incorrect number of path segment uuids in redo player", null);
/*      */       }
/*      */       
/* 7680 */       Folder folder = getFolderById(1);
/* 7681 */       for (int i = 0; i < parts.length; i++) {
/* 7682 */         boolean last = i == parts.length - 1;
/* 7683 */         int folderId = playerFolderIds == null ? -1 : playerFolderIds[i];
/* 7684 */         String folderUuid = playerFolderUuids == null ? UUIDUtil.generateUUID() : playerFolderUuids[i];
/*      */         
/* 7686 */         Folder subfolder = folder.findSubfolder(parts[i]);
/* 7687 */         if (subfolder == null) {
/* 7688 */           subfolder = Folder.create(getNextItemId(folderId), folderUuid, this, folder, parts[i], fopt.getAttributes(), last ? fopt.getDefaultView() : MailItem.Type.UNKNOWN, fopt.getFlags(), fopt.getColor(), fopt.getDate(), last ? fopt.getUrl() : null, fopt.getCustomMetadata());
/*      */         }
/*      */         else
/*      */         {
/* 7692 */           if ((folderId != -1) && (folderId != subfolder.getId()))
/* 7693 */             throw ServiceException.FAILURE("parent folder id changed since operation was recorded", null);
/* 7694 */           if (last) {
/* 7695 */             throw MailServiceException.ALREADY_EXISTS(path);
/*      */           }
/*      */         }
/* 7698 */         recorderFolderIds[i] = subfolder.getId();
/* 7699 */         recorderFolderUuids[i] = subfolder.getUuid();
/* 7700 */         folder = subfolder;
/*      */       }
/* 7702 */       redoRecorder.setFolderIdsAndUuids(recorderFolderIds, recorderFolderUuids);
/*      */       
/* 7704 */       success = true;
/* 7705 */       return folder;
/*      */     } finally {
/* 7707 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public String getItemFlagString(MailItem mi)
/*      */   {
/* 7713 */     return mi.getFlagString();
/*      */   }
/*      */   
/*      */   public ACL.Grant grantAccess(OperationContext octxt, int itemId, String grantee, byte granteeType, short rights, String args)
/*      */     throws ServiceException
/*      */   {
/* 7719 */     return grantAccess(octxt, itemId, grantee, granteeType, rights, args, 0L);
/*      */   }
/*      */   
/*      */ 
/*      */   public ACL.Grant grantAccess(OperationContext octxt, int itemId, String grantee, byte granteeType, short rights, String args, long expiry)
/*      */     throws ServiceException
/*      */   {
/* 7726 */     if ((rights & 0x100) != 0) {
/* 7727 */       if ((granteeType != 1) && (granteeType != 2))
/*      */       {
/* 7729 */         throw MailServiceException.CANNOT_GRANT("admin right can be granted to users and groups only"); }
/* 7730 */       if (granteeType == 1)
/*      */       {
/* 7732 */         Account account = Provisioning.getInstance().get(Key.AccountBy.id, grantee);
/* 7733 */         if ((account != null) && (account.isIsExternalVirtualAccount())) {
/* 7734 */           throw MailServiceException.CANNOT_GRANT("admin right cannot be granted to virtual users");
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 7739 */     GrantAccess redoPlayer = new GrantAccess(this.mId, itemId, grantee, granteeType, rights, args, expiry);
/*      */     
/* 7741 */     boolean success = false;
/* 7742 */     ACL.Grant grant = null;
/*      */     try {
/* 7744 */       beginTransaction("grantAccess", octxt, redoPlayer);
/*      */       
/* 7746 */       MailItem item = getItemById(itemId, MailItem.Type.UNKNOWN);
/* 7747 */       checkItemChangeID(item);
/*      */       
/* 7749 */       grant = item.grantAccess(grantee, granteeType, rights, args, expiry);
/* 7750 */       success = true;
/*      */     } finally {
/* 7752 */       endTransaction(success);
/*      */     }
/* 7754 */     return grant;
/*      */   }
/*      */   
/*      */   public void revokeAccess(OperationContext octxt, int itemId, String grantee) throws ServiceException {
/* 7758 */     revokeAccess(octxt, false, itemId, grantee);
/*      */   }
/*      */   
/*      */   public void revokeAccess(OperationContext octxt, boolean dueToExpiry, int itemId, String grantee) throws ServiceException
/*      */   {
/* 7763 */     RevokeAccess redoPlayer = new RevokeAccess(dueToExpiry, this.mId, itemId, grantee);
/*      */     
/* 7765 */     boolean success = false;
/*      */     try {
/* 7767 */       beginTransaction(dueToExpiry ? "expireAccess" : "revokeAccess", octxt, redoPlayer);
/*      */       
/* 7769 */       MailItem item = getItemById(itemId, MailItem.Type.UNKNOWN);
/* 7770 */       checkItemChangeID(item);
/* 7771 */       item.revokeAccess(grantee);
/* 7772 */       success = true;
/*      */     } finally {
/* 7774 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setPermissions(OperationContext octxt, int itemId, ACL acl) throws ServiceException {
/* 7779 */     SetPermissions redoPlayer = new SetPermissions(this.mId, itemId, acl);
/*      */     
/* 7781 */     boolean success = false;
/*      */     try {
/* 7783 */       beginTransaction("setPermissions", octxt, redoPlayer);
/*      */       
/* 7785 */       MailItem item = getItemById(itemId, MailItem.Type.UNKNOWN);
/* 7786 */       checkItemChangeID(item);
/* 7787 */       item.setPermissions(acl);
/* 7788 */       success = true;
/*      */     } finally {
/* 7790 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setRetentionPolicy(OperationContext octxt, int itemId, MailItem.Type type, RetentionPolicy rp) throws ServiceException
/*      */   {
/* 7796 */     if ((type != MailItem.Type.FOLDER) && (type != MailItem.Type.TAG)) {
/* 7797 */       throw ServiceException.FAILURE("Cannot set retention policy for " + type, null);
/*      */     }
/* 7799 */     if (rp == null) {
/* 7800 */       rp = new RetentionPolicy();
/*      */     } else {
/* 7802 */       validateRetentionPolicy(rp.getKeepPolicy());
/* 7803 */       validateRetentionPolicy(rp.getPurgePolicy());
/*      */     }
/*      */     
/* 7806 */     SetRetentionPolicy redoPlayer = new SetRetentionPolicy(this.mId, type, itemId, rp);
/*      */     
/* 7808 */     boolean success = false;
/*      */     try {
/* 7810 */       beginTransaction("setRetentionPolicy", octxt, redoPlayer);
/*      */       
/* 7812 */       if (type == MailItem.Type.FOLDER) {
/* 7813 */         Folder folder = getFolderById(itemId);
/* 7814 */         checkItemChangeID(folder);
/* 7815 */         folder.setRetentionPolicy(rp);
/*      */       } else {
/* 7817 */         Tag tag = getTagById(itemId);
/* 7818 */         checkItemChangeID(tag);
/* 7819 */         tag.setRetentionPolicy(rp);
/*      */       }
/* 7821 */       success = true;
/*      */     } finally {
/* 7823 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private void validateRetentionPolicy(List<Policy> list) throws ServiceException {
/* 7828 */     int numUser = 0;
/*      */     
/* 7830 */     for (Policy p : list) {
/* 7831 */       String lifetime = p.getLifetime();
/* 7832 */       if (!StringUtil.isNullOrEmpty(lifetime))
/*      */       {
/* 7834 */         DateUtil.getTimeInterval(lifetime);
/*      */       }
/* 7836 */       if (p.getType() == Policy.Type.USER) {
/* 7837 */         numUser++;
/*      */       }
/*      */     }
/*      */     
/* 7841 */     if (numUser > 1) {
/* 7842 */       throw ServiceException.INVALID_REQUEST("Cannot set more than one user retention policy per folder.", null);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setFolderDefaultView(OperationContext octxt, int folderId, MailItem.Type view) throws ServiceException {
/* 7847 */     SetFolderDefaultView redoRecorder = new SetFolderDefaultView(this.mId, folderId, view);
/*      */     
/* 7849 */     boolean success = false;
/*      */     try {
/* 7851 */       beginTransaction("setFolderDefaultView", octxt, redoRecorder);
/*      */       
/* 7853 */       Folder folder = getFolderById(folderId);
/* 7854 */       if (!checkItemChangeID(folder)) {
/* 7855 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/* 7857 */       folder.setDefaultView(view);
/* 7858 */       success = true;
/*      */     } finally {
/* 7860 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setFolderUrl(OperationContext octxt, int folderId, String url) throws ServiceException {
/* 7865 */     SetFolderUrl redoRecorder = new SetFolderUrl(this.mId, folderId, url);
/*      */     
/* 7867 */     boolean success = false;
/*      */     try {
/* 7869 */       beginTransaction("setFolderUrl", octxt, redoRecorder);
/*      */       
/* 7871 */       Folder folder = getFolderById(folderId);
/* 7872 */       checkItemChangeID(folder);
/* 7873 */       folder.setUrl(url);
/* 7874 */       success = true;
/* 7875 */       updateRssDataSource(folder);
/*      */     } finally {
/* 7877 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setFolderWebOfflineSyncDays(OperationContext octxt, int folderId, int days) throws ServiceException {
/* 7882 */     SetWebOfflineSyncDays redoRecorder = new SetWebOfflineSyncDays(this.mId, folderId, days);
/*      */     
/* 7884 */     boolean success = false;
/*      */     try {
/* 7886 */       beginTransaction("setFolderWebOfflineSyncDays", octxt, redoRecorder);
/*      */       
/* 7888 */       Folder folder = getFolderById(folderId);
/* 7889 */       if (!checkItemChangeID(folder)) {
/* 7890 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/* 7892 */       folder.setWebOfflineSyncDays(days);
/* 7893 */       success = true;
/*      */     } finally {
/* 7895 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   protected void updateRssDataSource(Folder folder)
/*      */   {
/*      */     try
/*      */     {
/* 7906 */       Provisioning prov = Provisioning.getInstance();
/* 7907 */       Account account = getAccount();
/* 7908 */       DataSource ds = null;
/* 7909 */       List<DataSource> dataSources = prov.getAllDataSources(account);
/* 7910 */       for (DataSource i : dataSources) {
/* 7911 */         if ((i.getFolderId() == folder.getId()) && ((i.getType() == DataSourceType.rss) || (i.getType() == DataSourceType.cal)))
/*      */         {
/* 7913 */           ds = i;
/* 7914 */           break;
/*      */         }
/*      */       }
/*      */       
/* 7918 */       if (StringUtil.isNullOrEmpty(folder.getUrl())) {
/* 7919 */         if (ds != null)
/*      */         {
/* 7921 */           String dsid = ds.getId();
/* 7922 */           prov.deleteDataSource(account, dsid);
/* 7923 */           DataSourceManager.cancelSchedule(account, dsid);
/*      */         }
/* 7925 */         return;
/*      */       }
/*      */       
/*      */ 
/* 7929 */       if (ds == null) {
/* 7930 */         Map<String, Object> attrs = new HashMap();
/* 7931 */         attrs.put("zimbraDataSourceEnabled", "TRUE");
/* 7932 */         attrs.put("zimbraDataSourceFolderId", Integer.toString(folder.getId()));
/*      */         String name;
/*      */         DataSourceType type;
/*      */         String name;
/* 7936 */         if (folder.getDefaultView() == MailItem.Type.APPOINTMENT) {
/* 7937 */           DataSourceType type = DataSourceType.cal;
/* 7938 */           name = "CAL-" + folder.getId();
/*      */         } else {
/* 7940 */           type = DataSourceType.rss;
/* 7941 */           name = "RSS-" + folder.getId();
/*      */         }
/*      */         
/* 7944 */         ds = prov.createDataSource(account, type, name, attrs);
/* 7945 */         DataSourceManager.updateSchedule(account, ds);
/*      */       }
/*      */     } catch (ServiceException e) {
/* 7948 */       ZimbraLog.mailbox.warn("Unable to update data source for folder %s.", folder.getPath(), e);
/*      */     }
/*      */   }
/*      */   
/*      */   public void synchronizeFolder(OperationContext octxt, int folderId) throws ServiceException {
/* 7953 */     importFeed(octxt, folderId, getFolderById(octxt, folderId).getUrl(), true);
/*      */   }
/*      */   
/*      */   public void importFeed(OperationContext octxt, int folderId, String url, boolean subscription) throws ServiceException {
/* 7957 */     if (StringUtil.isNullOrEmpty(url)) {
/* 7958 */       return;
/*      */     }
/*      */     
/*      */ 
/* 7962 */     Folder folder = getFolderById(octxt, folderId);
/* 7963 */     Folder.SyncData fsd = subscription ? folder.getSyncData() : null;
/* 7964 */     FeedManager.SubscriptionData<?> sdata = FeedManager.retrieveRemoteDatasource(getAccount(), url, fsd);
/* 7965 */     if (!sdata.isNotModified()) {
/* 7966 */       this.lock.lock();
/*      */       try {
/* 7968 */         importFeedInternal(octxt, folder, subscription, sdata);
/*      */       } finally {
/* 7970 */         this.lock.release();
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   private void importFeedInternal(OperationContext octxt, Folder folder, boolean subscription, FeedManager.SubscriptionData<?> sdata)
/*      */     throws ServiceException
/*      */   {
/* 7978 */     assert (this.lock.isWriteLockedByCurrentThread());
/*      */     
/*      */ 
/*      */ 
/* 7982 */     boolean isCalendar = (folder.getDefaultView() == MailItem.Type.APPOINTMENT) || (folder.getDefaultView() == MailItem.Type.TASK);
/*      */     
/* 7984 */     Set<Integer> toRemove = new HashSet();
/* 7985 */     Iterator i$; if ((subscription) && (isCalendar)) {
/* 7986 */       for (i$ = listItemIds(octxt, MailItem.Type.UNKNOWN, folder.getId()).iterator(); i$.hasNext();) { int i = ((Integer)i$.next()).intValue();
/* 7987 */         toRemove.add(Integer.valueOf(i));
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 7992 */     List<?> items = sdata.getItems();
/* 7993 */     if (items.isEmpty()) {
/* 7994 */       if ((subscription) && (isCalendar)) {
/* 7995 */         emptyFolder(octxt, folder.getId(), false);
/*      */       }
/* 7997 */       updateRssDataSource(folder);
/* 7998 */       return;
/*      */     }
/*      */     
/*      */ 
/* 8002 */     OperationContext octxtNoConflicts = null;
/* 8003 */     if (octxt != null) {
/* 8004 */       octxtNoConflicts = new OperationContext(octxt).unsetChangeConstraint();
/*      */     } else {
/* 8006 */       octxtNoConflicts = new OperationContext(getAccountId()).unsetChangeConstraint();
/*      */     }
/*      */     
/*      */ 
/* 8010 */     Set<String> calUidsSeen = new HashSet();
/* 8011 */     int numSkipped = 0;
/* 8012 */     for (Object obj : items) {
/*      */       try {
/* 8014 */         if ((obj instanceof Invite)) {
/* 8015 */           Invite inv = (Invite)obj;
/* 8016 */           String uid = inv.getUid();
/* 8017 */           if (uid == null) {
/* 8018 */             uid = UUIDUtil.generateUUID();
/* 8019 */             inv.setUid(uid);
/*      */           }
/*      */           
/* 8022 */           inv.setPartStat("AC");
/* 8023 */           inv.setRsvp(false);
/*      */           
/*      */           boolean addRevision;
/* 8026 */           if (!calUidsSeen.contains(uid)) {
/* 8027 */             boolean addRevision = true;
/* 8028 */             calUidsSeen.add(uid);
/*      */           } else {
/* 8030 */             addRevision = false;
/*      */           }
/*      */           try
/*      */           {
/* 8034 */             CalendarItem calItem = getCalendarItemByUid(octxtNoConflicts, uid);
/* 8035 */             boolean importIt; boolean importIt; if (calItem == null)
/*      */             {
/* 8037 */               importIt = true;
/*      */             } else {
/* 8039 */               toRemove.remove(Integer.valueOf(calItem.getId()));
/* 8040 */               Folder curFolder = calItem.getFolder();
/* 8041 */               boolean sameFolder = curFolder.getId() == folder.getId();
/* 8042 */               boolean inTrashOrSpam = (!sameFolder) && ((curFolder.inTrash()) || (curFolder.inSpam()));
/* 8043 */               boolean importIt; if (inTrashOrSpam)
/*      */               {
/*      */ 
/*      */ 
/* 8047 */                 delete(octxtNoConflicts, calItem.getId(), MailItem.Type.UNKNOWN);
/* 8048 */                 importIt = true;
/*      */               } else {
/* 8050 */                 Invite[] oldInvites = calItem.getInvites();
/* 8051 */                 boolean importIt; if ((oldInvites == null) || (oldInvites.length == 0))
/*      */                 {
/*      */ 
/* 8054 */                   delete(octxtNoConflicts, calItem.getId(), MailItem.Type.UNKNOWN);
/* 8055 */                   importIt = true;
/*      */ 
/*      */                 }
/*      */                 else
/*      */                 {
/*      */ 
/* 8061 */                   Invite curInv = calItem.getInvite(inv.getRecurId());
/* 8062 */                   boolean changed; boolean changed; if (curInv == null)
/*      */                   {
/*      */ 
/* 8065 */                     changed = true;
/*      */                   } else { boolean changed;
/* 8067 */                     if (inv.getSeqNo() > curInv.getSeqNo()) {
/* 8068 */                       changed = true; } else { boolean changed;
/* 8069 */                       if (inv.getSeqNo() == curInv.getSeqNo())
/*      */                       {
/* 8071 */                         changed = inv.getLastModified() > curInv.getLastModified();
/*      */                       } else
/* 8073 */                         changed = false;
/*      */                     }
/*      */                   }
/* 8076 */                   importIt = (sameFolder) && (changed);
/* 8077 */                   if ((!importIt) && (ZimbraLog.calendar.isDebugEnabled())) {
/* 8078 */                     if (sameFolder) {
/* 8079 */                       ZimbraLog.calendar.debug("Skip importing UID=%s. Already present & not newer", new Object[] { uid });
/*      */                     } else {
/* 8081 */                       ZimbraLog.calendar.debug("Skip importing UID=%s. Already in different folder id=%d", new Object[] { uid, Integer.valueOf(curFolder.getId()) });
/*      */                     }
/*      */                   }
/*      */                 }
/*      */               }
/*      */             }
/*      */             
/* 8088 */             if (importIt) {
/* 8089 */               addInvite(octxtNoConflicts, inv, folder.getId(), true, addRevision);
/*      */             } else {
/* 8091 */               numSkipped++;
/*      */             }
/*      */           } catch (ServiceException e) {
/* 8094 */             ZimbraLog.calendar.warn("Skipping bad iCalendar object UID=%s during import into folder id=%d", inv.getUid(), Integer.valueOf(folder.getId()), e);
/*      */           }
/*      */         }
/* 8097 */         else if ((obj instanceof ParsedMessage)) {
/* 8098 */           DeliveryOptions dopt = new DeliveryOptions().setFolderId(folder).setNoICal(true).setFlags(Flag.BITMASK_UNREAD);
/* 8099 */           addMessage(octxtNoConflicts, (ParsedMessage)obj, dopt, null);
/*      */         }
/*      */       } catch (IOException e) {
/* 8102 */         throw ServiceException.FAILURE("IOException", e);
/*      */       }
/*      */     }
/*      */     
/* 8106 */     if (numSkipped > 0) {
/* 8107 */       ZimbraLog.calendar.warn("Skipped importing %d iCalendar objects with clashing UIDs", new Object[] { Integer.valueOf(numSkipped) });
/*      */     }
/*      */     
/* 8110 */     for (Iterator i$ = toRemove.iterator(); i$.hasNext();) { int i = ((Integer)i$.next()).intValue();
/* 8111 */       delete(octxtNoConflicts, i, MailItem.Type.UNKNOWN);
/*      */     }
/*      */     
/*      */ 
/* 8115 */     long lastModDate = sdata.getLastModifiedDate();
/* 8116 */     if ((subscription) && (lastModDate > 0L)) {
/*      */       try {
/* 8118 */         setSubscriptionData(octxt, folder.getId(), lastModDate, sdata.getMostRecentGuid());
/*      */       } catch (Exception e) {
/* 8120 */         ZimbraLog.mailbox.warn("could not update feed metadata", e);
/*      */       }
/*      */     }
/*      */     
/* 8124 */     updateRssDataSource(folder);
/*      */   }
/*      */   
/*      */   public void setSubscriptionData(OperationContext octxt, int folderId, long date, String uuid) throws ServiceException
/*      */   {
/* 8129 */     SetSubscriptionData redoRecorder = new SetSubscriptionData(this.mId, folderId, date, uuid);
/*      */     
/* 8131 */     boolean success = false;
/*      */     try {
/* 8133 */       beginTransaction("setSubscriptionData", octxt, redoRecorder);
/* 8134 */       getFolderById(folderId).setSubscriptionData(uuid, date);
/* 8135 */       success = true;
/*      */     } finally {
/* 8137 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setSyncDate(OperationContext octxt, int folderId, long date) throws ServiceException {
/* 8142 */     SetSubscriptionData redoRecorder = new SetSubscriptionData(this.mId, folderId, date, null);
/*      */     
/* 8144 */     boolean success = false;
/*      */     try {
/* 8146 */       beginTransaction("setSyncDate", octxt, redoRecorder);
/* 8147 */       getFolderById(folderId).setSyncDate(date);
/* 8148 */       success = true;
/*      */     } finally {
/* 8150 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void setActiveSyncDisabled(OperationContext octxt, int folderId, boolean disableActiveSync) throws ServiceException {
/* 8155 */     SetActiveSyncDisabled redoRecorder = new SetActiveSyncDisabled(this.mId, folderId, disableActiveSync);
/*      */     
/* 8157 */     boolean success = false;
/*      */     try {
/* 8159 */       beginTransaction("setActiveSyncDisabled", octxt, redoRecorder);
/* 8160 */       getFolderById(folderId).setActiveSyncDisabled(disableActiveSync);
/* 8161 */       success = true;
/*      */     } finally {
/* 8163 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private boolean deletedBatchOfItemsInFolder(OperationContext octxt, DbMailItem.QueryParams params, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/* 8170 */     this.lock.lock();
/*      */     try {
/* 8172 */       DeleteItem redoRecorder = new DeleteItem(this.mId, MailItem.Type.UNKNOWN, tcon);
/* 8173 */       boolean success = false;
/*      */       try {
/* 8175 */         beginTransaction("delete", octxt, redoRecorder);
/* 8176 */         setOperationTargetConstraint(tcon);
/* 8177 */         MailItem.PendingDelete info = DbMailItem.getLeafNodes(this, params);
/* 8178 */         if (info.itemIds.isEmpty()) {
/* 8179 */           boolean bool1 = false;
/*      */           
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 8185 */           endTransaction(success);
/*      */           
/*      */ 
/* 8188 */           return bool1;
/*      */         }
/* 8181 */         redoRecorder.setIds(ArrayUtil.toIntArray(info.itemIds.getAllIds()));
/* 8182 */         MailItem.delete(this, info, null, true, false);
/* 8183 */         success = true;
/*      */       } finally {
/* 8185 */         endTransaction(success);
/*      */       }
/*      */     } finally {
/* 8188 */       this.lock.release();
/*      */     }
/* 8190 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   private void emptyFolder(OperationContext octxt, int folderId, boolean removeTopLevelFolder, boolean removeSubfolders, MailItem.TargetConstraint tcon)
/*      */     throws ServiceException
/*      */   {
/*      */     try
/*      */     {
/* 8200 */       if ((this.emptyFolderOpLock.tryLock()) || (this.emptyFolderOpLock.tryLock(Provisioning.getInstance().getLocalServer().getEmptyFolderOpTimeout(), TimeUnit.SECONDS)))
/*      */       {
/*      */ 
/* 8203 */         int batchSize = Provisioning.getInstance().getLocalServer().getMailEmptyFolderBatchSize();
/* 8204 */         ZimbraLog.mailbox.debug("Emptying folder %s, removeTopLevelFolder=%b, removeSubfolders=%b, batchSize=%d", new Object[] { Integer.valueOf(folderId), Boolean.valueOf(removeTopLevelFolder), Boolean.valueOf(removeSubfolders), Integer.valueOf(batchSize) });
/*      */         
/* 8206 */         List<Integer> folderIds = new ArrayList();
/* 8207 */         if (!removeSubfolders) {
/* 8208 */           folderIds.add(Integer.valueOf(folderId));
/*      */         } else {
/* 8210 */           List<Folder> folders = getFolderById(octxt, folderId).getSubfolderHierarchy();
/* 8211 */           for (Folder folder : folders) {
/* 8212 */             folderIds.add(Integer.valueOf(folder.getId()));
/*      */           }
/*      */         }
/*      */         
/* 8216 */         for (Iterator i$ = folderIds.iterator(); i$.hasNext();) { int id = ((Integer)i$.next()).intValue();
/* 8217 */           if ((getEffectivePermissions(octxt, id, MailItem.Type.FOLDER) & 0x8) == 0) {
/* 8218 */             throw ServiceException.PERM_DENIED("not authorized to empty folder " + getFolderById(octxt, id).getPath());
/*      */           }
/*      */         }
/*      */         
/* 8222 */         int lastChangeID = (octxt != null) && (octxt.change != -1) ? octxt.change : getLastChangeID();
/*      */         
/* 8224 */         DbMailItem.QueryParams params = new DbMailItem.QueryParams();
/* 8225 */         params.setFolderIds(folderIds).setModifiedSequenceBefore(Integer.valueOf(lastChangeID + 1)).setRowLimit(Integer.valueOf(batchSize));
/* 8226 */         boolean firstTime = true;
/*      */         do
/*      */         {
/* 8229 */           if (firstTime) {
/* 8230 */             firstTime = false;
/*      */           } else {
/* 8232 */             long sleepMillis = LC.empty_folder_batch_sleep_ms.longValue();
/*      */             try {
/* 8234 */               ZimbraLog.mailbox.debug("emptyLargeFolder() sleeping for %dms", new Object[] { Long.valueOf(sleepMillis) });
/* 8235 */               Thread.sleep(sleepMillis);
/*      */             } catch (InterruptedException e) {
/* 8237 */               ZimbraLog.mailbox.warn("Sleep was interrupted", e);
/*      */             }
/*      */           }
/* 8240 */         } while (deletedBatchOfItemsInFolder(octxt, params, tcon));
/* 8241 */         if (((removeTopLevelFolder) || (removeSubfolders)) && (!folderIds.isEmpty())) {
/* 8242 */           if (!removeTopLevelFolder) {
/* 8243 */             folderIds.remove(0);
/*      */           }
/* 8245 */           if (!folderIds.isEmpty()) {
/* 8246 */             this.lock.lock();
/*      */             try {
/* 8248 */               delete(octxt, ArrayUtil.toIntArray(folderIds), MailItem.Type.FOLDER, tcon, false, null);
/*      */             } finally {
/* 8250 */               this.lock.release();
/*      */             }
/*      */           }
/*      */         }
/*      */       } else {
/* 8255 */         ZimbraLog.mailbox.info("Empty large folder operation canceled because previous empty folder operation is in progress");
/*      */         
/* 8257 */         throw ServiceException.ALREADY_IN_PROGRESS("Empty Folder operation is in progress. Please wait for the operation to complete");
/*      */       }
/*      */     }
/*      */     catch (InterruptedException e) {
/* 8261 */       ZimbraLog.mailbox.warn("Empty folder operation interupted while acquiring emptyFolderOpLock", e);
/* 8262 */       throw ServiceException.ALREADY_IN_PROGRESS("Empty Folder operation is in progress. Please wait for the operation to complete");
/*      */     }
/*      */     finally {
/* 8265 */       if (this.emptyFolderOpLock.isHeldByCurrentThread()) {
/* 8266 */         this.emptyFolderOpLock.unlock();
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   public void emptyFolder(OperationContext octxt, int folderId, boolean removeSubfolders) throws ServiceException
/*      */   {
/* 8273 */     emptyFolder(octxt, folderId, false, removeSubfolders, null);
/*      */   }
/*      */   
/*      */   public SearchFolder createSearchFolder(OperationContext octxt, int folderId, String name, String query, String types, String sort, int flags, byte color)
/*      */     throws ServiceException
/*      */   {
/* 8279 */     return createSearchFolder(octxt, folderId, name, query, types, sort, flags, new Color(color));
/*      */   }
/*      */   
/*      */   public SearchFolder createSearchFolder(OperationContext octxt, int folderId, String name, String query, String types, String sort, int flags, Color color)
/*      */     throws ServiceException
/*      */   {
/* 8285 */     CreateSavedSearch redoRecorder = new CreateSavedSearch(this.mId, folderId, name, query, types, sort, flags, color);
/*      */     
/* 8287 */     boolean success = false;
/*      */     try {
/* 8289 */       beginTransaction("createSearchFolder", octxt, redoRecorder);
/* 8290 */       CreateSavedSearch redoPlayer = (CreateSavedSearch)currentChange().getRedoPlayer();
/*      */       
/* 8292 */       int searchId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getSearchId());
/* 8293 */       String uuid = redoPlayer == null ? UUIDUtil.generateUUID() : redoPlayer.getUuid();
/* 8294 */       SearchFolder search = SearchFolder.create(searchId, uuid, getFolderById(folderId), name, query, types, sort, flags, color, null);
/*      */       
/* 8296 */       redoRecorder.setSearchIdAndUuid(search.getId(), search.getUuid());
/* 8297 */       success = true;
/* 8298 */       return search;
/*      */     } finally {
/* 8300 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void modifySearchFolder(OperationContext octxt, int id, String query, String types, String sort) throws ServiceException
/*      */   {
/* 8306 */     ModifySavedSearch redoRecorder = new ModifySavedSearch(this.mId, id, query, types, sort);
/*      */     
/* 8308 */     boolean success = false;
/*      */     try {
/* 8310 */       beginTransaction("modifySearchFolder", octxt, redoRecorder);
/*      */       
/* 8312 */       SearchFolder search = getSearchFolderById(id);
/* 8313 */       checkItemChangeID(search);
/*      */       
/* 8315 */       search.changeQuery(query, types, sort);
/* 8316 */       success = true;
/*      */     } finally {
/* 8318 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Mountpoint createMountpoint(OperationContext octxt, int folderId, String name, String ownerId, int remoteId, String remoteUuid, MailItem.Type view, int flags, byte color, boolean showReminders)
/*      */     throws ServiceException
/*      */   {
/* 8325 */     return createMountpoint(octxt, folderId, name, ownerId, remoteId, remoteUuid, view, flags, new Color(color), showReminders);
/*      */   }
/*      */   
/*      */ 
/*      */   public Mountpoint createMountpoint(OperationContext octxt, int folderId, String name, String ownerId, int remoteId, String remoteUuid, MailItem.Type view, int flags, Color color, boolean showReminders)
/*      */     throws ServiceException
/*      */   {
/* 8332 */     CreateMountpoint redoRecorder = new CreateMountpoint(this.mId, folderId, name, ownerId, remoteId, remoteUuid, view, flags, color, showReminders);
/*      */     
/*      */ 
/* 8335 */     boolean success = false;
/*      */     try {
/* 8337 */       beginTransaction("createMountpoint", octxt, redoRecorder);
/* 8338 */       CreateMountpoint redoPlayer = (CreateMountpoint)currentChange().getRedoPlayer();
/*      */       
/* 8340 */       int mptId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getId());
/* 8341 */       String uuid = redoPlayer == null ? UUIDUtil.generateUUID() : redoPlayer.getUuid();
/* 8342 */       Mountpoint mpt = Mountpoint.create(mptId, uuid, getFolderById(folderId), name, ownerId, remoteId, remoteUuid, view, flags, color, showReminders, null);
/*      */       
/* 8344 */       redoRecorder.setIdAndUuid(mpt.getId(), mpt.getUuid());
/* 8345 */       success = true;
/* 8346 */       return mpt;
/*      */     } finally {
/* 8348 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Mountpoint refreshMountpoint(OperationContext octxt, int mountpointId)
/*      */     throws ServiceException
/*      */   {
/* 8361 */     Mountpoint mp = getMountpointById(octxt, mountpointId);
/* 8362 */     Provisioning prov = Provisioning.getInstance();
/* 8363 */     ShareLocator shloc = prov.getShareLocatorById(mp.getRemoteUuid());
/* 8364 */     if ((shloc == null) || (mp.getOwnerId().equalsIgnoreCase(shloc.getShareOwnerAccountId())))
/*      */     {
/* 8366 */       return mp;
/*      */     }
/*      */     
/*      */ 
/* 8370 */     Account shareOwner = Provisioning.getInstance().get(Key.AccountBy.id, shloc.getShareOwnerAccountId());
/* 8371 */     AuthToken at = AuthToken.getCsrfUnsecuredAuthToken(octxt.getAuthToken());
/* 8372 */     String pxyAuthToken = Provisioning.onLocalServer(shareOwner) ? null : at.getProxyAuthToken();
/* 8373 */     ZAuthToken zat = null;
/* 8374 */     if (pxyAuthToken == null) {
/* 8375 */       zat = at.toZAuthToken();
/* 8376 */       zat.resetProxyAuthToken();
/*      */     } else {
/* 8378 */       zat = new ZAuthToken(pxyAuthToken);
/*      */     }
/* 8380 */     ZMailbox.Options zoptions = new ZMailbox.Options(zat, AccountUtil.getSoapUri(shareOwner));
/* 8381 */     zoptions.setNoSession(true);
/* 8382 */     zoptions.setTargetAccount(shareOwner.getId());
/* 8383 */     zoptions.setTargetAccountBy(Key.AccountBy.id);
/* 8384 */     ZMailbox zmbx = ZMailbox.getMailbox(zoptions);
/* 8385 */     ZFolder zfolder = zmbx.getFolderByUuid(shloc.getUuid());
/*      */     
/* 8387 */     if (zfolder != null) {
/* 8388 */       ItemId fid = new ItemId(zfolder.getId(), shareOwner.getId());
/* 8389 */       return refreshMountpoint(octxt, mountpointId, shareOwner.getId(), fid.getId());
/*      */     }
/* 8391 */     return null;
/*      */   }
/*      */   
/*      */   public Mountpoint refreshMountpoint(OperationContext octxt, int mountpointId, String ownerId, int remoteId)
/*      */     throws ServiceException
/*      */   {
/* 8397 */     RefreshMountpoint redoRecorder = new RefreshMountpoint(this.mId, mountpointId, ownerId, remoteId);
/* 8398 */     boolean success = false;
/*      */     try {
/* 8400 */       beginTransaction("refreshMountpoint", octxt, redoRecorder);
/* 8401 */       Mountpoint mpt = getMountpointById(octxt, mountpointId);
/* 8402 */       mpt.setRemoteInfo(ownerId, remoteId);
/* 8403 */       success = true;
/*      */     } finally {
/* 8405 */       endTransaction(success);
/*      */     }
/*      */     
/* 8408 */     return getMountpointById(octxt, mountpointId);
/*      */   }
/*      */   
/*      */   public void enableSharedReminder(OperationContext octxt, int mountpointId, boolean enable) throws ServiceException {
/* 8412 */     EnableSharedReminder redoRecorder = new EnableSharedReminder(this.mId, mountpointId, enable);
/*      */     
/* 8414 */     boolean success = false;
/*      */     try {
/* 8416 */       beginTransaction("enableSharedReminders", octxt, redoRecorder);
/* 8417 */       Mountpoint mpt = getMountpointById(octxt, mountpointId);
/* 8418 */       mpt.enableReminder(enable);
/* 8419 */       success = true;
/*      */     } finally {
/* 8421 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean purgeMessages(OperationContext octxt)
/*      */     throws ServiceException
/*      */   {
/* 8431 */     Account acct = getAccount();
/* 8432 */     int maxItemsPerFolder = Provisioning.getInstance().getLocalServer().getMailPurgeBatchSize();
/* 8433 */     if (ZimbraLog.purge.isDebugEnabled()) {
/* 8434 */       ZimbraLog.purge.debug("System retention policy: Trash=%s, Junk=%s, All messages=%s, Dumpster=%s", new Object[] { acct.getMailTrashLifetimeAsString(), acct.getMailSpamLifetimeAsString(), acct.getMailMessageLifetimeAsString(), acct.getMailDumpsterLifetimeAsString() });
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 8439 */       ZimbraLog.purge.debug("User-specified retention policy: Inbox read=%s, Inbox unread=%s, Sent=%s, Junk=%s, Trash=%s, Versions=%s, VersionsEnabled=%s", new Object[] { acct.getPrefInboxReadLifetimeAsString(), acct.getPrefInboxUnreadLifetimeAsString(), acct.getPrefSentLifetimeAsString(), acct.getPrefJunkLifetimeAsString(), acct.getPrefTrashLifetimeAsString(), acct.getFileVersionLifetimeAsString(), Boolean.valueOf(acct.isFileVersioningEnabled()) });
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 8449 */     long globalTimeout = acct.getMailMessageLifetime();
/* 8450 */     long systemTrashTimeout = acct.getMailTrashLifetime();
/* 8451 */     long systemJunkTimeout = acct.getMailSpamLifetime();
/* 8452 */     boolean dumpsterPurgeEnabled = acct.isDumpsterPurgeEnabled();
/* 8453 */     long systemDumpsterTimeoutMillis = dumpsterPurgeEnabled ? acct.getMailDumpsterLifetime() : 0L;
/*      */     
/* 8455 */     long userInboxReadTimeout = acct.getPrefInboxReadLifetime();
/* 8456 */     long userInboxUnreadTimeout = acct.getPrefInboxUnreadLifetime();
/* 8457 */     long userTrashTimeout = acct.getPrefTrashLifetime();
/* 8458 */     long userJunkTimeout = acct.getPrefJunkLifetime();
/* 8459 */     long userSentTimeout = acct.getPrefSentLifetime();
/*      */     
/* 8461 */     long trashTimeout = pickTimeout(systemTrashTimeout, userTrashTimeout);
/* 8462 */     long spamTimeout = pickTimeout(systemJunkTimeout, userJunkTimeout);
/*      */     
/* 8464 */     boolean userFileVersioningEnabled = acct.isFileVersioningEnabled();
/* 8465 */     long userFileVersionLifeTime = acct.getFileVersionLifetime();
/*      */     
/* 8467 */     if ((globalTimeout <= 0L) && (trashTimeout <= 0L) && (spamTimeout <= 0L) && (userInboxReadTimeout <= 0L) && (userInboxReadTimeout <= 0L) && (userInboxUnreadTimeout <= 0L) && (userSentTimeout <= 0L) && (systemDumpsterTimeoutMillis <= 0L) && ((!userFileVersioningEnabled) || (userFileVersionLifeTime <= 0L)))
/*      */     {
/*      */ 
/* 8470 */       ZimbraLog.purge.debug("Retention policy does not require purge.");
/* 8471 */       return true;
/*      */     }
/*      */     
/* 8474 */     ZimbraLog.purge.info("Purging messages.");
/*      */     
/*      */ 
/* 8477 */     if ((globalTimeout > 0L) && (globalTimeout < 2678400000L))
/*      */     {
/* 8479 */       ZimbraLog.purge.warn("global message timeout < 1 month; defaulting to 31 days");
/* 8480 */       globalTimeout = 2678400000L;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 8485 */     purgeExpiredIMAPDeletedMessages(trashTimeout);
/*      */     
/* 8487 */     PurgeOldMessages redoRecorder = new PurgeOldMessages(this.mId);
/*      */     
/* 8489 */     boolean success = false;
/*      */     try {
/* 8491 */       beginTransaction("purgeMessages", octxt, redoRecorder);
/*      */       
/*      */ 
/* 8494 */       Folder trash = getFolderById(3);
/* 8495 */       Folder spam = getFolderById(4);
/* 8496 */       Folder sent = getFolderById(5);
/* 8497 */       Folder inbox = getFolderById(2);
/*      */       
/* 8499 */       boolean purgedAll = true;
/*      */       
/* 8501 */       if (globalTimeout > 0L) {
/* 8502 */         int numPurged = Folder.purgeMessages(this, null, getOperationTimestampMillis() - globalTimeout, null, false, false, Integer.valueOf(maxItemsPerFolder));
/* 8503 */         ZimbraLog.purge.debug("Purged %d messages from All Folders", new Object[] { Integer.valueOf(numPurged) });
/* 8504 */         purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/*      */       }
/* 8506 */       if (trashTimeout > 0L) {
/* 8507 */         boolean useChangeDate = acct.getBooleanAttr("zimbraMailPurgeUseChangeDateForTrash", true);
/* 8508 */         int numPurged = Folder.purgeMessages(this, trash, getOperationTimestampMillis() - trashTimeout, null, useChangeDate, true, Integer.valueOf(maxItemsPerFolder));
/* 8509 */         ZimbraLog.purge.debug("Purged %d messages from Trash", new Object[] { Integer.valueOf(numPurged) });
/* 8510 */         purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/*      */       }
/* 8512 */       if (spamTimeout > 0L) {
/* 8513 */         boolean useChangeDate = acct.isMailPurgeUseChangeDateForSpam();
/* 8514 */         int numPurged = Folder.purgeMessages(this, spam, getOperationTimestampMillis() - spamTimeout, null, useChangeDate, false, Integer.valueOf(maxItemsPerFolder));
/* 8515 */         purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/* 8516 */         ZimbraLog.purge.debug("Purged %d messages from Spam", new Object[] { Integer.valueOf(numPurged) });
/*      */       }
/* 8518 */       if (userInboxReadTimeout > 0L) {
/* 8519 */         int numPurged = Folder.purgeMessages(this, inbox, getOperationTimestampMillis() - userInboxReadTimeout, Boolean.valueOf(false), false, false, Integer.valueOf(maxItemsPerFolder));
/* 8520 */         purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/* 8521 */         ZimbraLog.purge.debug("Purged %d read messages from Inbox", new Object[] { Integer.valueOf(numPurged) });
/*      */       }
/* 8523 */       if (userInboxUnreadTimeout > 0L) {
/* 8524 */         int numPurged = Folder.purgeMessages(this, inbox, getOperationTimestampMillis() - userInboxUnreadTimeout, Boolean.valueOf(true), false, false, Integer.valueOf(maxItemsPerFolder));
/* 8525 */         purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/* 8526 */         ZimbraLog.purge.debug("Purged %d unread messages from Inbox", new Object[] { Integer.valueOf(numPurged) });
/*      */       }
/* 8528 */       if (userSentTimeout > 0L) {
/* 8529 */         int numPurged = Folder.purgeMessages(this, sent, getOperationTimestampMillis() - userSentTimeout, null, false, false, Integer.valueOf(maxItemsPerFolder));
/* 8530 */         purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/* 8531 */         ZimbraLog.purge.debug("Purged %d messages from Sent", new Object[] { Integer.valueOf(numPurged) });
/*      */       }
/* 8533 */       if (systemDumpsterTimeoutMillis > 0L) {
/* 8534 */         int numPurged = purgeDumpster(getOperationTimestampMillis() - systemDumpsterTimeoutMillis, maxItemsPerFolder);
/* 8535 */         ZimbraLog.purge.debug("Purged %d messages from Dumpster", new Object[] { Integer.valueOf(numPurged) });
/* 8536 */         purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/*      */       }
/*      */       
/* 8539 */       if ((userFileVersioningEnabled) && (userFileVersionLifeTime > 0L)) {
/* 8540 */         int numPurged = MailItem.purgeRevisions(this, getOperationTimestampMillis() - userFileVersionLifeTime);
/* 8541 */         ZimbraLog.purge.debug("Purged %d revisions", new Object[] { Integer.valueOf(numPurged) });
/*      */       }
/*      */       
/* 8544 */       for (Iterator i$ = getFolderList(octxt, SortBy.NONE).iterator(); i$.hasNext();) { folder = (Folder)i$.next();
/* 8545 */         RetentionPolicy rp = RetentionPolicyManager.getInstance().getCompleteRetentionPolicy(acct, folder.getRetentionPolicy());
/* 8546 */         for (Policy policy : rp.getPurgePolicy())
/*      */         {
/*      */           long folderLifetime;
/*      */           try {
/* 8550 */             folderLifetime = DateUtil.getTimeInterval(policy.getLifetime());
/*      */           } catch (ServiceException e) {
/* 8552 */             ZimbraLog.purge.error("Invalid purge lifetime set for folder %s.", folder.getPath(), e); }
/* 8553 */           continue;
/*      */           
/*      */ 
/* 8556 */           long folderTimeout = getOperationTimestampMillis() - folderLifetime;
/* 8557 */           int numPurged = Folder.purgeMessages(this, folder, folderTimeout, null, false, false, Integer.valueOf(maxItemsPerFolder));
/* 8558 */           purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/*      */         }
/*      */       }
/*      */       
/*      */       Folder folder;
/* 8563 */       for (Iterator i$ = getTagList(octxt).iterator(); i$.hasNext();) { tag = (Tag)i$.next();
/* 8564 */         RetentionPolicy rp = RetentionPolicyManager.getInstance().getCompleteRetentionPolicy(acct, tag.getRetentionPolicy());
/* 8565 */         for (Policy policy : rp.getPurgePolicy()) {
/*      */           long tagLifetime;
/*      */           try {
/* 8568 */             tagLifetime = DateUtil.getTimeInterval(policy.getLifetime());
/*      */           } catch (ServiceException e) {
/* 8570 */             ZimbraLog.purge.error("Invalid purge lifetime set for tag %s.", tag.getName(), e); }
/* 8571 */           continue;
/*      */           
/*      */ 
/* 8574 */           long tagTimeout = getOperationTimestampMillis() - tagLifetime;
/* 8575 */           MailItem.PendingDelete info = DbTag.getLeafNodes(this, tag, (int)(tagTimeout / 1000L), Integer.valueOf(maxItemsPerFolder));
/* 8576 */           MailItem.delete(this, info, null, false, false);
/* 8577 */           List<Integer> ids = info.itemIds.getIds(MailItem.Type.MESSAGE);
/* 8578 */           int numPurged = ids == null ? 0 : ids.size();
/* 8579 */           purgedAll = updatePurgedAll(purgedAll, numPurged, Integer.valueOf(maxItemsPerFolder));
/*      */         }
/*      */       }
/*      */       
/*      */       Tag tag;
/* 8584 */       TypedIdList tombstones = collectPendingTombstones();
/* 8585 */       if ((tombstones != null) && (!tombstones.isEmpty())) {
/* 8586 */         DbMailItem.writeTombstones(this, tombstones);
/*      */       }
/*      */       
/* 8589 */       if (Threader.isHashPurgeAllowed(acct)) {
/* 8590 */         int convTimeoutSecs = (int)(LC.conversation_max_age_ms.longValue() / 1000L);
/* 8591 */         DbMailItem.closeOldConversations(this, getOperationTimestamp() - convTimeoutSecs);
/*      */       }
/*      */       int tombstoneTimeoutSecs;
/* 8594 */       if (isTrackingSync()) {
/* 8595 */         tombstoneTimeoutSecs = (int)(LC.tombstone_max_age_ms.longValue() / 1000L);
/* 8596 */         int largestTrimmed = DbMailItem.purgeTombstones(this, getOperationTimestamp() - tombstoneTimeoutSecs);
/* 8597 */         if (largestTrimmed > getSyncCutoff()) {
/* 8598 */           currentChange().sync = Integer.valueOf(largestTrimmed);
/* 8599 */           DbMailbox.setSyncCutoff(this, currentChange().sync.intValue());
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 8604 */       if (purgedAll) {
/* 8605 */         DbMailbox.updateLastPurgeAt(this, System.currentTimeMillis());
/*      */       }
/*      */       
/* 8608 */       success = true;
/* 8609 */       ZimbraLog.purge.debug("purgedAll=%b", new Object[] { Boolean.valueOf(purgedAll) });
/* 8610 */       return purgedAll;
/*      */     } finally {
/* 8612 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   private boolean updatePurgedAll(boolean purgedAll, int numDeleted, Integer maxItems) {
/* 8617 */     return (purgedAll) && ((maxItems == null) || (numDeleted < maxItems.intValue()));
/*      */   }
/*      */   
/*      */ 
/*      */   private long pickTimeout(long t1, long t2)
/*      */   {
/* 8623 */     if (t1 == 0L) {
/* 8624 */       return t2;
/*      */     }
/* 8626 */     if (t2 == 0L) {
/* 8627 */       return t1;
/*      */     }
/* 8629 */     return Math.min(t1, t2);
/*      */   }
/*      */   
/*      */   public void purgeImapDeleted(OperationContext octxt) throws ServiceException {
/* 8633 */     PurgeImapDeleted redoRecorder = new PurgeImapDeleted(this.mId);
/* 8634 */     boolean success = false;
/*      */     try {
/* 8636 */       beginTransaction("purgeImapDeleted", octxt, redoRecorder);
/*      */       
/* 8638 */       Set<Folder> purgeable = getAccessibleFolders((short)9);
/*      */       
/*      */ 
/* 8641 */       boolean skipDB = false;
/* 8642 */       if (getVersion().atLeast(1, 9)) {
/* 8643 */         int deleted = 0;
/* 8644 */         for (Folder folder : purgeable != null ? purgeable : listAllFolders()) {
/* 8645 */           deleted += folder.getDeletedCount();
/*      */         }
/* 8647 */         skipDB = deleted == 0;
/*      */       }
/*      */       
/* 8650 */       if (!skipDB) {
/* 8651 */         MailItem.PendingDelete info = DbTag.getImapDeleted(this, purgeable);
/* 8652 */         MailItem.delete(this, info, null, true, false);
/*      */       }
/* 8654 */       success = true;
/*      */     } finally {
/* 8656 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public WikiItem createWiki(OperationContext octxt, int folderId, String wikiword, String author, String description, InputStream data) throws ServiceException
/*      */   {
/* 8662 */     return (WikiItem)createDocument(octxt, folderId, wikiword, "text/html; charset=utf-8", author, description, true, data, MailItem.Type.WIKI);
/*      */   }
/*      */   
/*      */   public Document createDocument(OperationContext octxt, int folderId, String filename, String mimeType, String author, String description, InputStream data)
/*      */     throws ServiceException
/*      */   {
/* 8668 */     return createDocument(octxt, folderId, filename, mimeType, author, description, true, data, MailItem.Type.DOCUMENT);
/*      */   }
/*      */   
/*      */   public Document createDocument(OperationContext octxt, int folderId, String filename, String mimeType, String author, String description, boolean descEnabled, InputStream data, MailItem.Type type) throws ServiceException
/*      */   {
/*      */     try
/*      */     {
/* 8675 */       ParsedDocument pd = new ParsedDocument(data, filename, mimeType, System.currentTimeMillis(), author, description, descEnabled);
/* 8676 */       return createDocument(octxt, folderId, pd, type, 0);
/*      */     } catch (IOException ioe) {
/* 8678 */       throw ServiceException.FAILURE("error writing document blob", ioe);
/*      */     }
/*      */   }
/*      */   
/*      */   public Document createDocument(OperationContext octxt, int folderId, ParsedDocument pd, MailItem.Type type, int flags)
/*      */     throws IOException, ServiceException
/*      */   {
/* 8685 */     StoreManager sm = StoreManager.getInstance();
/* 8686 */     StagedBlob staged = sm.stage(pd.getBlob(), this);
/*      */     
/* 8688 */     SaveDocument redoRecorder = new SaveDocument(this.mId, pd.getDigest(), pd.getSize(), folderId, flags);
/*      */     
/* 8690 */     boolean success = false;
/*      */     try {
/* 8692 */       long start = System.currentTimeMillis();
/*      */       
/* 8694 */       beginTransaction("createDoc", octxt, redoRecorder);
/*      */       
/* 8696 */       SaveDocument redoPlayer = octxt == null ? null : (SaveDocument)octxt.getPlayer();
/* 8697 */       int itemId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getMessageId());
/* 8698 */       String uuid = redoPlayer == null ? UUIDUtil.generateUUID() : redoPlayer.getUuid();
/*      */       
/*      */       Document doc;
/* 8701 */       switch (type) {
/*      */       case DOCUMENT: 
/* 8703 */         doc = Document.create(itemId, uuid, getFolderById(folderId), pd.getFilename(), pd.getContentType(), pd, null, flags);
/* 8704 */         break;
/*      */       case WIKI: 
/* 8706 */         doc = WikiItem.create(itemId, uuid, getFolderById(folderId), pd.getFilename(), pd, null);
/* 8707 */         break;
/*      */       default: 
/* 8709 */         throw MailServiceException.INVALID_TYPE(type.toString());
/*      */       }
/*      */       
/* 8712 */       redoRecorder.setMessageId(itemId);
/* 8713 */       redoRecorder.setUuid(doc.getUuid());
/* 8714 */       redoRecorder.setDocument(pd);
/* 8715 */       redoRecorder.setItemType(type);
/* 8716 */       redoRecorder.setDescription(pd.getDescription());
/* 8717 */       redoRecorder.setFlags(doc.getFlagBitmask());
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 8723 */       MailboxBlob mailboxBlob = doc.setContent(staged, pd);
/* 8724 */       redoRecorder.setMessageBodyInfo(new MailboxBlobDataSource(mailboxBlob), mailboxBlob.getSize());
/*      */       
/* 8726 */       this.index.add(doc);
/*      */       
/* 8728 */       success = true;
/* 8729 */       long elapsed = System.currentTimeMillis() - start;
/* 8730 */       ZimbraLog.mailbox.debug("createDocument elapsed=" + elapsed);
/* 8731 */       return doc;
/*      */     } catch (IOException ioe) {
/* 8733 */       throw ServiceException.FAILURE("error writing document blob", ioe);
/*      */     } finally {
/* 8735 */       endTransaction(success);
/* 8736 */       sm.quietDelete(staged);
/*      */     }
/*      */   }
/*      */   
/*      */   public Document addDocumentRevision(OperationContext octxt, int docId, String author, String name, String description, InputStream data) throws ServiceException
/*      */   {
/* 8742 */     Document doc = getDocumentById(octxt, docId);
/*      */     try {
/* 8744 */       ParsedDocument pd = new ParsedDocument(data, name, doc.getContentType(), System.currentTimeMillis(), author, description, doc.isDescriptionEnabled());
/* 8745 */       return addDocumentRevision(octxt, docId, pd);
/*      */     } catch (IOException ioe) {
/* 8747 */       throw ServiceException.FAILURE("error writing document blob", ioe);
/*      */     }
/*      */   }
/*      */   
/*      */   public Document addDocumentRevision(OperationContext octxt, int docId, String author, String name, String description, boolean descEnabled, InputStream data) throws ServiceException
/*      */   {
/* 8753 */     Document doc = getDocumentById(octxt, docId);
/*      */     try {
/* 8755 */       ParsedDocument pd = new ParsedDocument(data, name, doc.getContentType(), System.currentTimeMillis(), author, description, descEnabled);
/* 8756 */       return addDocumentRevision(octxt, docId, pd);
/*      */     } catch (IOException ioe) {
/* 8758 */       throw ServiceException.FAILURE("error writing document blob", ioe);
/*      */     }
/*      */   }
/*      */   
/*      */   public Document addDocumentRevision(OperationContext octxt, int docId, ParsedDocument pd)
/*      */     throws IOException, ServiceException
/*      */   {
/* 8765 */     StoreManager sm = StoreManager.getInstance();
/* 8766 */     StagedBlob staged = sm.stage(pd.getBlob(), this);
/*      */     
/* 8768 */     AddDocumentRevision redoRecorder = new AddDocumentRevision(this.mId, pd.getDigest(), pd.getSize(), 0);
/*      */     
/* 8770 */     boolean success = false;
/*      */     try {
/* 8772 */       beginTransaction("addDocumentRevision", octxt, redoRecorder);
/*      */       
/* 8774 */       Document doc = getDocumentById(docId);
/* 8775 */       redoRecorder.setDocument(pd);
/* 8776 */       redoRecorder.setDocId(docId);
/* 8777 */       redoRecorder.setItemType(doc.getType());
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 8784 */       MailboxBlob mailboxBlob = doc.setContent(staged, pd);
/* 8785 */       redoRecorder.setMessageBodyInfo(new MailboxBlobDataSource(mailboxBlob), mailboxBlob.getSize());
/*      */       
/* 8787 */       this.index.add(doc);
/*      */       
/* 8789 */       success = true;
/* 8790 */       return doc;
/*      */     } catch (IOException ioe) {
/* 8792 */       throw ServiceException.FAILURE("error writing document blob", ioe);
/*      */     } finally {
/* 8794 */       endTransaction(success);
/* 8795 */       sm.quietDelete(staged);
/*      */     }
/*      */   }
/*      */   
/*      */   public void purgeRevision(OperationContext octxt, int itemId, int rev, boolean includeOlderRevisions) throws ServiceException
/*      */   {
/* 8801 */     PurgeRevision redoRecorder = new PurgeRevision(this.mId, itemId, rev, includeOlderRevisions);
/* 8802 */     boolean success = false;
/*      */     try {
/* 8804 */       beginTransaction("purgeRevision", octxt, redoRecorder);
/* 8805 */       MailItem item = getItemById(itemId, MailItem.Type.DOCUMENT);
/* 8806 */       item.purgeRevision(rev, includeOlderRevisions);
/* 8807 */       success = true;
/*      */     } finally {
/* 8809 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Message updateOrCreateChat(OperationContext octxt, ParsedMessage pm, int id) throws IOException, ServiceException
/*      */   {
/* 8815 */     if (id == -1) {
/* 8816 */       return createChat(octxt, pm, 14, Flag.BITMASK_FROM_ME, null);
/*      */     }
/* 8818 */     return updateChat(octxt, pm, id);
/*      */   }
/*      */   
/*      */   public Chat createChat(OperationContext octxt, ParsedMessage pm, int folderId, int flags, String[] tags)
/*      */     throws IOException, ServiceException
/*      */   {
/* 8824 */     if (pm == null) {
/* 8825 */       throw ServiceException.INVALID_REQUEST("null ParsedMessage when adding chat to mailbox " + this.mId, null);
/*      */     }
/*      */     
/*      */ 
/* 8829 */     StoreManager sm = StoreManager.getInstance();
/*      */     
/* 8831 */     InputStream is = pm.getRawInputStream();
/*      */     StagedBlob staged;
/* 8833 */     try { staged = sm.stage(is, this);
/*      */     } finally {
/* 8835 */       ByteUtil.closeStream(is);
/*      */     }
/* 8837 */     String digest = staged.getDigest();
/* 8838 */     int size = (int)staged.getSize();
/*      */     
/* 8840 */     CreateChat redoRecorder = new CreateChat(this.mId, digest, size, folderId, flags, tags);
/* 8841 */     boolean success = false;
/*      */     try {
/* 8843 */       beginTransaction("createChat", octxt, redoRecorder);
/*      */       
/* 8845 */       Tag.NormalizedTags ntags = new Tag.NormalizedTags(this, tags);
/*      */       
/* 8847 */       CreateChat redoPlayer = octxt == null ? null : (CreateChat)octxt.getPlayer();
/* 8848 */       redoRecorder.setMessageBodyInfo(new ParsedMessageDataSource(pm), size);
/*      */       
/* 8850 */       int itemId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getMessageId());
/*      */       
/* 8852 */       Chat chat = Chat.create(itemId, getFolderById(folderId), pm, staged, false, flags, ntags);
/* 8853 */       redoRecorder.setMessageId(chat.getId());
/*      */       
/* 8855 */       MailboxBlob mblob = sm.link(staged, this, itemId, getOperationChangeID());
/* 8856 */       markOtherItemDirty(mblob);
/*      */       
/*      */ 
/* 8859 */       chat.updateBlobData(mblob);
/*      */       
/* 8861 */       this.index.add(chat);
/* 8862 */       success = true;
/* 8863 */       return chat;
/*      */     } finally {
/* 8865 */       endTransaction(success);
/* 8866 */       sm.quietDelete(staged);
/*      */     }
/*      */   }
/*      */   
/*      */   public Chat updateChat(OperationContext octxt, ParsedMessage pm, int id) throws IOException, ServiceException {
/* 8871 */     if (pm == null) {
/* 8872 */       throw ServiceException.INVALID_REQUEST("null ParsedMessage when updating chat " + id + " in mailbox " + this.mId, null);
/*      */     }
/*      */     
/*      */ 
/* 8876 */     StoreManager sm = StoreManager.getInstance();
/*      */     
/* 8878 */     InputStream is = pm.getRawInputStream();
/*      */     StagedBlob staged;
/* 8880 */     try { staged = sm.stage(is, this);
/*      */     } finally {
/* 8882 */       ByteUtil.closeStream(is);
/*      */     }
/*      */     
/* 8885 */     String digest = staged.getDigest();
/* 8886 */     int size = (int)staged.getSize();
/*      */     
/* 8888 */     SaveChat redoRecorder = new SaveChat(this.mId, id, digest, size, -1, 0, null);
/* 8889 */     boolean success = false;
/*      */     try {
/* 8891 */       beginTransaction("saveChat", octxt, redoRecorder);
/*      */       
/* 8893 */       SaveChat redoPlayer = (SaveChat)currentChange().getRedoPlayer();
/*      */       
/* 8895 */       redoRecorder.setMessageBodyInfo(new ParsedMessageDataSource(pm), size);
/*      */       
/* 8897 */       Chat chat = (Chat)getItemById(id, MailItem.Type.CHAT);
/*      */       
/* 8899 */       if (!chat.isMutable()) {
/* 8900 */         throw MailServiceException.IMMUTABLE_OBJECT(id);
/*      */       }
/* 8902 */       if (!checkItemChangeID(chat)) {
/* 8903 */         throw MailServiceException.MODIFY_CONFLICT(new ServiceException.Argument[0]);
/*      */       }
/*      */       
/*      */ 
/* 8907 */       int imapID = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getImapId());
/* 8908 */       redoRecorder.setImapId(imapID);
/*      */       
/*      */ 
/* 8911 */       chat.setContent(staged, pm);
/*      */       
/*      */ 
/* 8914 */       this.index.add(chat);
/*      */       
/* 8916 */       success = true;
/* 8917 */       return chat;
/*      */     } finally {
/* 8919 */       endTransaction(success);
/* 8920 */       sm.quietDelete(staged);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public void optimize(int level)
/*      */   {
/* 8928 */     this.lock.lock();
/*      */     try {
/* 8930 */       DbPool.DbConnection conn = DbPool.getConnection(this);
/*      */       
/* 8932 */       DbMailbox.optimize(conn, this, level);
/* 8933 */       DbPool.quietClose(conn);
/*      */     } catch (Exception e) {
/* 8935 */       ZimbraLog.mailbox.warn("db optimize failed for mailbox " + getId() + ": " + e);
/*      */     } finally {
/* 8937 */       this.lock.release();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   private static class SharedDeliveryCoordinator
/*      */   {
/*      */     public int mNumDelivs;
/*      */     
/*      */ 
/*      */     public boolean mSharedDeliveryAllowed;
/*      */     
/*      */ 
/*      */     public SharedDeliveryCoordinator()
/*      */     {
/* 8953 */       this.mNumDelivs = 0;
/* 8954 */       this.mSharedDeliveryAllowed = true;
/*      */     }
/*      */   }
/*      */   
/* 8958 */   private final SharedDeliveryCoordinator mSharedDelivCoord = new SharedDeliveryCoordinator();
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean beginSharedDelivery()
/*      */   {
/* 8977 */     synchronized (this.mSharedDelivCoord) {
/* 8978 */       assert (this.mSharedDelivCoord.mNumDelivs >= 0);
/* 8979 */       if (this.mSharedDelivCoord.mSharedDeliveryAllowed) {
/* 8980 */         this.mSharedDelivCoord.mNumDelivs += 1;
/* 8981 */         if (ZimbraLog.mailbox.isDebugEnabled()) {
/* 8982 */           ZimbraLog.mailbox.debug("# of shared deliv incr to " + this.mSharedDelivCoord.mNumDelivs + " for mailbox " + getId());
/*      */         }
/*      */         
/* 8985 */         return true;
/*      */       }
/*      */       
/*      */ 
/* 8989 */       return false;
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public void endSharedDelivery()
/*      */   {
/* 8998 */     synchronized (this.mSharedDelivCoord) {
/* 8999 */       this.mSharedDelivCoord.mNumDelivs -= 1;
/* 9000 */       if (ZimbraLog.mailbox.isDebugEnabled()) {
/* 9001 */         ZimbraLog.mailbox.debug("# of shared deliv decr to " + this.mSharedDelivCoord.mNumDelivs + " for mailbox " + getId());
/*      */       }
/*      */       
/* 9004 */       assert (this.mSharedDelivCoord.mNumDelivs >= 0);
/* 9005 */       if (this.mSharedDelivCoord.mNumDelivs == 0)
/*      */       {
/* 9007 */         this.mSharedDelivCoord.notifyAll();
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void setSharedDeliveryAllowed(boolean onoff)
/*      */   {
/* 9020 */     synchronized (this.mSharedDelivCoord) {
/* 9021 */       if (onoff)
/*      */       {
/* 9023 */         this.mSharedDelivCoord.mSharedDeliveryAllowed = true;
/*      */       }
/*      */       else {
/* 9026 */         this.mSharedDelivCoord.mSharedDeliveryAllowed = false;
/*      */       }
/* 9028 */       this.mSharedDelivCoord.notifyAll();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void waitUntilSharedDeliveryCompletes()
/*      */   {
/* 9039 */     synchronized (this.mSharedDelivCoord) {
/* 9040 */       while (this.mSharedDelivCoord.mNumDelivs > 0) {
/*      */         try {
/* 9042 */           this.mSharedDelivCoord.wait(3000L);
/* 9043 */           ZimbraLog.misc.info("wake up from wait for completion of shared delivery; mailbox=" + getId() + " # of shared deliv=" + this.mSharedDelivCoord.mNumDelivs);
/*      */         }
/*      */         catch (InterruptedException e) {}
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean isSharedDeliveryComplete()
/*      */   {
/* 9055 */     synchronized (this.mSharedDelivCoord) {
/* 9056 */       return this.mSharedDelivCoord.mNumDelivs < 1;
/*      */     }
/*      */   }
/*      */   
/*      */   void addIndexItemToCurrentChange(IndexItemEntry item) {
/* 9061 */     assert (this.lock.isWriteLockedByCurrentThread());
/* 9062 */     assert (currentChange().isActive());
/* 9063 */     currentChange().addIndexItem(item);
/*      */   }
/*      */   
/*      */ 
/*      */   void migrateFolderView(OperationContext octxt, Folder f, MailItem.Type newView)
/*      */     throws ServiceException
/*      */   {
/* 9070 */     boolean success = false;
/*      */     try {
/* 9072 */       beginTransaction("migrateFolderView", octxt, null);
/* 9073 */       f.migrateDefaultView(newView);
/* 9074 */       success = true;
/*      */     } finally {
/* 9076 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   protected boolean needRedo(OperationContext octxt, RedoableOp recorder)
/*      */   {
/* 9082 */     if ((!this.open) && (!(recorder instanceof CreateMailbox))) {
/* 9083 */       return false;
/*      */     }
/* 9085 */     return (octxt == null) || (octxt.needRedo());
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected void endTransaction(boolean success)
/*      */     throws ServiceException
/*      */   {
/* 9097 */     assert (!Thread.holdsLock(this)) : "Use MailboxLock";
/* 9098 */     if (this.lock.isUnlocked()) {
/* 9099 */       ZimbraLog.mailbox.warn("transaction canceled because of lock failure");
/* 9100 */       assert (!success);
/* 9101 */       return;
/*      */     }
/* 9103 */     MailItem.PendingDelete deletes = null;
/* 9104 */     List<Object> rollbackDeletes = null;
/*      */     StoreManager sm;
/* 9106 */     try { StoreManager sm; Iterator i$; MailboxBlob blob; StoreManager sm; Iterator i$; Object obj; if (!currentChange().isActive())
/*      */       {
/*      */ 
/* 9109 */         ZimbraLog.mailbox.warn("cannot end a transaction when not inside a transaction", new Exception());
/*      */       }
/*      */       else {
/* 9112 */         if (!currentChange().endChange()) { StoreManager sm;
/*      */           Iterator i$;
/*      */           MailboxBlob blob;
/*      */           StoreManager sm; Iterator i$; Object obj; return; } ServiceException exception = null;
/*      */         
/* 9117 */         if (success) {
/* 9118 */           List<IndexItemEntry> indexItems = currentChange().indexItems;
/* 9119 */           if (!indexItems.isEmpty()) {
/* 9120 */             assert (currentChange().writeChange);
/*      */             
/*      */ 
/* 9123 */             currentChange().indexItems = new ArrayList();
/* 9124 */             this.index.add(indexItems);
/*      */           }
/*      */           
/*      */           try
/*      */           {
/* 9129 */             snapshotCounts();
/*      */           } catch (ServiceException e) {
/* 9131 */             exception = e;
/* 9132 */             success = false;
/*      */           }
/*      */         }
/*      */         
/* 9136 */         DbPool.DbConnection conn = currentChange().conn;
/*      */         StoreManager sm;
/*      */         Iterator i$;
/*      */         MailboxBlob blob;
/*      */         StoreManager sm;
/* 9141 */         Iterator i$; Object obj; if (!success) {
/* 9142 */           DbPool.quietRollback(conn);
/* 9143 */           rollbackDeletes = rollbackCache(currentChange());
/* 9144 */           if (exception != null) {
/* 9145 */             throw exception;
/*      */           }
/*      */         }
/*      */         else
/*      */         {
/* 9150 */           RedoableOp redoRecorder = currentChange().recorder;
/* 9151 */           boolean needRedo = needRedo(currentChange().octxt, redoRecorder);
/*      */           
/* 9153 */           if ((redoRecorder != null) && (needRedo)) {
/* 9154 */             redoRecorder.log(true);
/*      */           }
/* 9156 */           boolean dbCommitSuccess = false;
/*      */           try
/*      */           {
/* 9159 */             if (conn != null) {
/*      */               try {
/* 9161 */                 conn.commit();
/*      */ 
/*      */ 
/*      */               }
/*      */               catch (Throwable t)
/*      */               {
/*      */ 
/* 9168 */                 Zimbra.halt("Unable to commit database transaction.  Forcing server to abort.", t);
/*      */               }
/*      */             }
/* 9171 */             dbCommitSuccess = true; } finally { StoreManager sm;
/*      */             Iterator i$;
/* 9173 */             MailboxBlob blob; StoreManager sm; Iterator i$; Object obj; if (!dbCommitSuccess)
/*      */             {
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 9180 */               if ((needRedo) && 
/* 9181 */                 (redoRecorder != null)) {
/* 9182 */                 redoRecorder.abort();
/*      */               }
/*      */               
/* 9185 */               DbPool.quietRollback(conn);
/* 9186 */               rollbackDeletes = rollbackCache(currentChange());
/*      */               StoreManager sm;
/*      */               Iterator i$;
/*      */               MailboxBlob blob;
/*      */               StoreManager sm;
/*      */               Iterator i$; Object obj; return; } } if (needRedo)
/*      */           {
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 9198 */             if (redoRecorder != null) {
/* 9199 */               if ((currentChange().dirty != null) && (!currentChange().dirty.changedTypes.isEmpty()))
/*      */               {
/*      */ 
/* 9202 */                 AllAccountsRedoCommitCallback cb = AllAccountsRedoCommitCallback.getRedoCallbackIfNecessary(getAccountId(), currentChange().dirty.changedTypes);
/*      */                 
/* 9204 */                 if (cb != null) {
/* 9205 */                   redoRecorder.setCommitCallback(cb);
/*      */                 }
/*      */               }
/* 9208 */               redoRecorder.commit();
/*      */             }
/*      */           }
/*      */           
/* 9212 */           boolean changeMade = currentChange().changeId != -1;
/* 9213 */           deletes = currentChange().deletes;
/*      */           
/*      */ 
/*      */ 
/* 9217 */           commitCache(currentChange());
/*      */           
/*      */ 
/*      */ 
/*      */ 
/* 9222 */           if (changeMade)
/* 9223 */             this.index.maybeIndexDeferredItems(); } } } finally { StoreManager sm;
/*      */       Iterator i$;
/*      */       MailboxBlob blob;
/* 9226 */       StoreManager sm; Iterator i$; Object obj; this.lock.release();
/*      */       
/*      */       StoreManager sm;
/*      */       
/* 9230 */       if (deletes != null) {
/* 9231 */         if (!deletes.indexIds.isEmpty())
/*      */         {
/* 9233 */           this.index.delete(deletes.indexIds);
/*      */         }
/* 9235 */         if (deletes.blobs != null)
/*      */         {
/* 9237 */           sm = StoreManager.getInstance();
/* 9238 */           for (MailboxBlob blob : deletes.blobs) {
/* 9239 */             sm.quietDelete(blob);
/*      */           }
/*      */         }
/*      */       }
/* 9243 */       if (rollbackDeletes != null) {
/* 9244 */         sm = StoreManager.getInstance();
/* 9245 */         for (Object obj : rollbackDeletes) {
/* 9246 */           if ((obj instanceof MailboxBlob)) {
/* 9247 */             sm.quietDelete((MailboxBlob)obj);
/* 9248 */           } else if ((obj instanceof Blob)) {
/* 9249 */             sm.quietDelete((Blob)obj);
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/* 9257 */   public static final int NON_DELIVERY_FLAGS = Flag.BITMASK_DRAFT | Flag.BITMASK_FROM_ME | Flag.BITMASK_COPIED | Flag.BITMASK_DELETED;
/*      */   
/*      */   void snapshotCounts() throws ServiceException
/*      */   {
/* 9261 */     OperationContext octxt = currentChange().octxt;
/* 9262 */     RedoableOp player = currentChange().getRedoPlayer();
/* 9263 */     RedoableOp recorder = currentChange().recorder;
/*      */     
/* 9265 */     if ((recorder != null) && ((player == null) || ((octxt != null) && (!octxt.isRedo())))) {
/* 9266 */       assert (currentChange().writeChange);
/* 9267 */       boolean isNewMessage = recorder.getOperation() == MailboxOperation.CreateMessage;
/* 9268 */       if (isNewMessage) {
/* 9269 */         CreateMessage cm = (CreateMessage)recorder;
/* 9270 */         if ((cm.getFolderId() == 4) || (cm.getFolderId() == 3)) {
/* 9271 */           isNewMessage = false;
/* 9272 */         } else if ((cm.getFlags() & NON_DELIVERY_FLAGS) != 0) {
/* 9273 */           isNewMessage = false;
/* 9274 */         } else if ((octxt != null) && (octxt.getSession() != null) && (!octxt.isDelegatedRequest(this))) {
/* 9275 */           isNewMessage = false;
/*      */         }
/*      */         
/* 9278 */         if (isNewMessage) {
/* 9279 */           String folderList = getAccount().getPrefMailFoldersCheckedForNewMsgIndicator();
/*      */           
/* 9281 */           if (folderList != null) {
/* 9282 */             String[] folderIds = folderList.split(",");
/*      */             
/* 9284 */             isNewMessage = false;
/* 9285 */             for (int i = 0; i < folderIds.length; i++) {
/* 9286 */               if (cm.getFolderId() == Integer.parseInt(folderIds[i])) {
/* 9287 */                 isNewMessage = true;
/* 9288 */                 break;
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 9295 */       if (isNewMessage) {
/* 9296 */         currentChange().recent = (this.mData.recentMessages + 1);
/* 9297 */       } else if ((octxt != null) && (this.mData.recentMessages != 0)) {
/* 9298 */         Session s = octxt.getSession();
/* 9299 */         if (((s instanceof SoapSession)) || (((s instanceof SoapSession.DelegateSession)) && (((SoapSession.DelegateSession)s).getParentSession().isOfflineSoapSession())))
/*      */         {
/*      */ 
/* 9302 */           currentChange().recent = 0;
/*      */         }
/*      */       }
/*      */     }
/*      */     
/* 9307 */     if (currentChange().isMailboxRowDirty(this.mData)) {
/* 9308 */       assert (currentChange().writeChange);
/* 9309 */       if (currentChange().recent != -1) {
/* 9310 */         ZimbraLog.mailbox.debug("setting recent count to %d", new Object[] { Integer.valueOf(currentChange().recent) });
/*      */       }
/* 9312 */       DbMailbox.updateMailboxStats(this);
/*      */     }
/*      */     
/* 9315 */     boolean foldersTagsDirty = false;
/* 9316 */     if ((currentChange().dirty != null) && (currentChange().dirty.hasNotifications())) {
/* 9317 */       assert (currentChange().writeChange);
/* 9318 */       if (currentChange().dirty.created != null) {
/* 9319 */         for (MailItem item : currentChange().dirty.created.values()) {
/* 9320 */           if ((item instanceof Folder)) {
/* 9321 */             foldersTagsDirty = true;
/* 9322 */             if (item.getSize() != 0L) {
/* 9323 */               ((Folder)item).saveFolderCounts(false);
/*      */             }
/* 9325 */           } else if ((item instanceof Tag)) {
/* 9326 */             foldersTagsDirty = true;
/* 9327 */             if (item.isUnread()) {
/* 9328 */               ((Tag)item).saveTagCounts();
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 9334 */       if (currentChange().dirty.modified != null) {
/* 9335 */         for (PendingModifications.Change change : currentChange().dirty.modified.values()) {
/* 9336 */           if ((change.what instanceof Folder)) {
/* 9337 */             foldersTagsDirty = true;
/* 9338 */             if ((change.why & 0x11) != 0) {
/* 9339 */               ((Folder)change.what).saveFolderCounts(false);
/*      */             }
/* 9341 */           } else if ((change.what instanceof Tag)) {
/* 9342 */             foldersTagsDirty = true;
/* 9343 */             if ((change.why & 0x1 | 0x10) != 0) {
/* 9344 */               ((Tag)change.what).saveTagCounts();
/*      */             }
/* 9346 */           } else if ((change.what instanceof MailItem)) {
/* 9347 */             if ((change.what instanceof Conversation)) {
/* 9348 */               uncache((MailItem)change.what);
/*      */             } else {
/* 9350 */               cache((MailItem)change.what);
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 9356 */       if (currentChange().dirty.deleted != null) {
/* 9357 */         for (PendingModifications.Change change : currentChange().dirty.deleted.values()) {
/* 9358 */           if (((change.what instanceof Folder)) || ((change.what instanceof Tag))) {
/* 9359 */             foldersTagsDirty = true;
/* 9360 */             break;
/*      */           }
/*      */         }
/*      */       }
/*      */       
/* 9365 */       if (foldersTagsDirty) {
/* 9366 */         cacheFoldersTagsToMemcached();
/*      */       }
/*      */     }
/*      */     
/* 9370 */     if ((DebugConfig.checkMailboxCacheConsistency) && (currentChange().dirty != null) && (currentChange().dirty.hasNotifications()))
/*      */     {
/* 9372 */       if (currentChange().dirty.created != null) {
/* 9373 */         for (MailItem item : currentChange().dirty.created.values()) {
/* 9374 */           DbMailItem.consistencyCheck(item, item.mData, item.encodeMetadata().toString());
/*      */         }
/*      */       }
/* 9377 */       if (currentChange().dirty.modified != null) {
/* 9378 */         for (PendingModifications.Change change : currentChange().dirty.modified.values()) {
/* 9379 */           if ((change.what instanceof MailItem)) {
/* 9380 */             MailItem item = (MailItem)change.what;
/* 9381 */             DbMailItem.consistencyCheck(item, item.mData, item.encodeMetadata().toString());
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   private void commitCache(MailboxChange change) {
/* 9389 */     if (change == null) {
/* 9390 */       return;
/*      */     }
/* 9392 */     MailboxListener.ChangeNotification notification = null;
/*      */     
/*      */ 
/* 9395 */     PendingModifications dirty = null;
/* 9396 */     if ((change.dirty != null) && (change.dirty.hasNotifications())) {
/* 9397 */       assert (this.lock.isWriteLockedByCurrentThread());
/* 9398 */       assert (currentChange().writeChange);
/* 9399 */       dirty = change.dirty;
/* 9400 */       change.dirty = new PendingModifications();
/*      */     }
/*      */     
/* 9403 */     Session source = change.octxt == null ? null : change.octxt.getSession();
/* 9404 */     assert ((!change.hasChanges()) || (this.lock.isWriteLockedByCurrentThread()));
/*      */     
/*      */     try
/*      */     {
/* 9408 */       if (change.sync != null) {
/* 9409 */         this.mData.trackSync = change.sync.intValue();
/*      */       }
/* 9411 */       if (change.imap != null) {
/* 9412 */         this.mData.trackImap = change.imap.booleanValue();
/*      */       }
/* 9414 */       if (change.size != -1L) {
/* 9415 */         this.mData.size = change.size;
/*      */       }
/* 9417 */       if (change.itemId != -1) {
/* 9418 */         this.mData.lastItemId = change.itemId;
/*      */       }
/* 9420 */       if (change.contacts != -1) {
/* 9421 */         this.mData.contacts = change.contacts;
/*      */       }
/* 9423 */       if ((change.changeId != -1) && (change.changeId > this.mData.lastChangeId)) {
/* 9424 */         this.mData.lastChangeId = change.changeId;
/* 9425 */         this.mData.lastChangeDate = change.timestamp;
/*      */       }
/* 9427 */       if (change.accessed != -1) {
/* 9428 */         this.mData.lastWriteDate = change.accessed;
/*      */       }
/* 9430 */       if (change.recent != -1) {
/* 9431 */         this.mData.recentMessages = change.recent;
/*      */       }
/* 9433 */       if (change.config != null) {
/* 9434 */         if (change.config.getSecond() == null) {
/* 9435 */           if (this.mData.configKeys != null) {
/* 9436 */             this.mData.configKeys.remove(change.config.getFirst());
/*      */           }
/*      */         } else {
/* 9439 */           if (this.mData.configKeys == null) {
/* 9440 */             this.mData.configKeys = new HashSet(1);
/*      */           }
/* 9442 */           this.mData.configKeys.add(change.config.getFirst());
/*      */         }
/*      */       }
/*      */       
/* 9446 */       if ((change.deletes != null) && (change.deletes.blobs != null))
/*      */       {
/* 9448 */         for (String digest : change.deletes.blobDigests) {
/* 9449 */           MessageCache.purge(digest);
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 9454 */       if ((dirty != null) && (dirty.hasNotifications()))
/*      */       {
/*      */         try {
/* 9457 */           dirty = snapshotModifications(dirty);
/*      */         } catch (ServiceException e) {
/* 9459 */           ZimbraLog.mailbox.warn("error copying notifications; will notify with live set", e);
/*      */         }
/*      */         try {
/* 9462 */           notification = new MailboxListener.ChangeNotification(getAccount(), dirty, change.octxt, this.mData.lastChangeId, change.getOperation(), change.timestamp);
/*      */         }
/*      */         catch (ServiceException e) {
/* 9465 */           ZimbraLog.mailbox.warn("error getting account for the mailbox", e);
/*      */         }
/*      */       }
/*      */     } catch (RuntimeException e) {
/* 9469 */       ZimbraLog.mailbox.error("ignoring error during cache commit", e);
/*      */     }
/*      */     finally {
/* 9472 */       trimItemCache();
/*      */       
/* 9474 */       change.reset();
/*      */     }
/*      */     
/* 9477 */     if (notification != null) {
/* 9478 */       for (Session session : this.mListeners) {
/*      */         try {
/* 9480 */           session.notifyPendingChanges(notification.mods, notification.lastChangeId, source);
/*      */         } catch (RuntimeException e) {
/* 9482 */           ZimbraLog.mailbox.error("ignoring error during notification", e);
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 9487 */       DbPool.DbConnection conn = null;
/*      */       try {
/* 9489 */         if (Zimbra.isAlwaysOn()) {
/* 9490 */           conn = DbPool.getConnection();
/* 9491 */           List<String> serverids = DbSession.get(conn, getId());
/* 9492 */           for (String serverid : serverids) {
/* 9493 */             Server server = Provisioning.getInstance().getServerById(serverid);
/* 9494 */             if (!server.isLocalServer())
/*      */             {
/*      */ 
/* 9497 */               MailboxNotification ntfn = MailboxNotification.create(getAccountId(), this.mData.lastChangeId, dirty.getSerializedBytes());
/* 9498 */               MessageChannel.getInstance().sendMessage(server, ntfn);
/*      */             }
/*      */           }
/*      */         }
/* 9502 */       } catch (ServiceException e) { ZimbraLog.session.warn("unable to get target server", e);
/*      */       } catch (MessageChannelException e) {
/* 9504 */         ZimbraLog.session.warn("unable to create MailboxNotification", e); return;
/*      */       }
/*      */       catch (IOException e) {
/* 9507 */         ZimbraLog.session.warn("unable to create MailboxNotification", e); return;
/*      */       }
/*      */       finally {
/* 9510 */         if (conn != null) {
/* 9511 */           conn.closeQuietly();
/*      */         }
/*      */       }
/* 9514 */       MailboxListener.notifyListeners(notification);
/*      */     }
/*      */   }
/*      */   
/*      */   private List<Object> rollbackCache(MailboxChange change) {
/* 9519 */     if (change == null) {
/* 9520 */       return null;
/*      */     }
/*      */     try
/*      */     {
/* 9524 */       for (Map<?, ?> map : new Map[] { change.dirty.created, change.dirty.deleted, change.dirty.modified }) {
/* 9525 */         if (map != null) {
/* 9526 */           for (Object obj : map.values()) {
/* 9527 */             if ((obj instanceof PendingModifications.Change)) {
/* 9528 */               obj = ((PendingModifications.Change)obj).what;
/*      */             }
/*      */             
/* 9531 */             if (((obj instanceof Tag)) || (obj == MailItem.Type.TAG)) {
/* 9532 */               purge(MailItem.Type.TAG);
/* 9533 */             } else if (((obj instanceof Folder)) || (FOLDER_TYPES.contains(obj))) {
/* 9534 */               purge(MailItem.Type.FOLDER);
/* 9535 */             } else if (((obj instanceof MailItem)) && (change.itemCache != null)) {
/* 9536 */               change.itemCache.remove(((MailItem)obj).getId());
/*      */             }
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/* 9543 */       List<Object> deletes = new ArrayList(change.otherDirtyStuff.size());
/* 9544 */       for (Object obj : change.otherDirtyStuff) {
/* 9545 */         if (((obj instanceof MailboxBlob)) || ((obj instanceof Blob))) {
/* 9546 */           deletes.add(obj);
/* 9547 */         } else if ((obj instanceof String)) {
/* 9548 */           this.mConvHashes.remove(obj);
/*      */         }
/*      */       }
/* 9551 */       return deletes;
/*      */     } catch (RuntimeException e) {
/* 9553 */       ZimbraLog.mailbox.error("ignoring error during cache rollback", e);
/* 9554 */       return null;
/*      */     }
/*      */     finally {
/* 9557 */       trimItemCache();
/*      */       
/* 9559 */       change.reset();
/*      */     }
/*      */   }
/*      */   
/*      */   private void trimItemCache() {
/*      */     try {
/* 9565 */       int sizeTarget = this.mListeners.isEmpty() ? MAX_ITEM_CACHE_WITHOUT_LISTENERS : MAX_ITEM_CACHE_WITH_LISTENERS;
/* 9566 */       if (this.galSyncMailbox) {
/* 9567 */         sizeTarget = MAX_ITEM_CACHE_FOR_GALSYNC_MAILBOX;
/*      */       }
/*      */       
/* 9570 */       ItemCache cache = currentChange().itemCache;
/* 9571 */       if (cache == null) {
/* 9572 */         return;
/*      */       }
/*      */       
/* 9575 */       int excess = cache.size() - sizeTarget;
/* 9576 */       if (excess <= 0) {
/* 9577 */         return;
/*      */       }
/*      */       
/*      */ 
/* 9581 */       MailItem[] overflow = new MailItem[excess];
/* 9582 */       int i = 0;
/* 9583 */       for (MailItem item : cache.values()) {
/* 9584 */         overflow[(i++)] = item;
/* 9585 */         if (i >= excess) {
/*      */           break;
/*      */         }
/*      */       }
/*      */       for (;;) {
/* 9590 */         i--; if (i < 0) break;
/* 9591 */         if (cache.size() <= sizeTarget) {
/* 9592 */           return;
/*      */         }
/*      */         try
/*      */         {
/* 9596 */           uncache(overflow[i]);
/*      */         }
/*      */         catch (ServiceException e) {}
/*      */       }
/*      */     } catch (RuntimeException e) {
/* 9601 */       ZimbraLog.mailbox.error("ignoring error during item cache trim", e);
/*      */     }
/*      */   }
/*      */   
/*      */   public boolean attachmentsIndexingEnabled() throws ServiceException {
/* 9606 */     return getAccount().isAttachmentsIndexingEnabled();
/*      */   }
/*      */   
/*      */   private void logCacheActivity(Object key, MailItem.Type type, MailItem item)
/*      */   {
/* 9611 */     if (!isCachedType(type)) {
/* 9612 */       ZimbraPerf.COUNTER_MBOX_ITEM_CACHE.increment(item == null ? 0L : 100L);
/*      */     }
/*      */     
/*      */ 
/* 9616 */     if (!ZimbraLog.cache.isDebugEnabled()) {
/* 9617 */       return;
/*      */     }
/*      */     
/* 9620 */     if (item == null) {
/* 9621 */       ZimbraLog.cache.debug("Cache miss for item " + key + " in mailbox " + getId());
/* 9622 */       return;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/* 9627 */     if (isCachedType(type)) {
/* 9628 */       return;
/*      */     }
/* 9630 */     ZimbraLog.cache.debug("Cache hit for %s %d in mailbox %d", new Object[] { type, key, Integer.valueOf(getId()) });
/*      */   }
/*      */   
/*      */   public MailItem lock(OperationContext octxt, int itemId, MailItem.Type type, String accountId) throws ServiceException
/*      */   {
/* 9635 */     LockItem redoRecorder = new LockItem(this.mId, itemId, type, accountId);
/*      */     
/* 9637 */     boolean success = false;
/*      */     try {
/* 9639 */       beginTransaction("lock", octxt, redoRecorder);
/* 9640 */       MailItem item = getItemById(itemId, type);
/* 9641 */       item.lock(Provisioning.getInstance().getAccountById(accountId));
/* 9642 */       success = true;
/* 9643 */       return item;
/*      */     } finally {
/* 9645 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public void unlock(OperationContext octxt, int itemId, MailItem.Type type, String accountId) throws ServiceException
/*      */   {
/* 9651 */     UnlockItem redoRecorder = new UnlockItem(this.mId, itemId, type, accountId);
/*      */     
/* 9653 */     boolean success = false;
/*      */     try {
/* 9655 */       beginTransaction("unlock", octxt, redoRecorder);
/* 9656 */       MailItem item = getItemById(itemId, type);
/* 9657 */       item.unlock(Provisioning.getInstance().getAccountById(accountId));
/* 9658 */       success = true;
/*      */     } finally {
/* 9660 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Comment createComment(OperationContext octxt, int parentId, String text, String creatorId) throws ServiceException
/*      */   {
/* 9666 */     CreateComment redoRecorder = new CreateComment(this.mId, parentId, text, creatorId);
/*      */     
/* 9668 */     boolean success = false;
/*      */     try {
/* 9670 */       beginTransaction("createComment", octxt, redoRecorder);
/*      */       
/* 9672 */       MailItem parent = getItemById(octxt, parentId, MailItem.Type.UNKNOWN);
/* 9673 */       if (parent.getType() != MailItem.Type.DOCUMENT) {
/* 9674 */         throw MailServiceException.CANNOT_PARENT();
/*      */       }
/* 9676 */       CreateComment redoPlayer = (CreateComment)currentChange().getRedoPlayer();
/* 9677 */       int itemId = redoPlayer == null ? getNextItemId(-1) : redoPlayer.getItemId();
/* 9678 */       String uuid = redoPlayer == null ? UUIDUtil.generateUUID() : redoPlayer.getUuid();
/* 9679 */       Comment comment = Comment.create(this, parent, itemId, uuid, text, creatorId, null);
/* 9680 */       redoRecorder.setItemIdAndUuid(comment.getId(), comment.getUuid());
/* 9681 */       this.index.add(comment);
/* 9682 */       success = true;
/* 9683 */       return comment;
/*      */     } finally {
/* 9685 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Link createLink(OperationContext octxt, int folderId, String name, String ownerId, int remoteId) throws ServiceException {
/* 9690 */     CreateLink redoRecorder = new CreateLink(this.mId, folderId, name, ownerId, remoteId);
/*      */     
/* 9692 */     boolean success = false;
/*      */     try {
/* 9694 */       beginTransaction("createLink", octxt, redoRecorder);
/* 9695 */       CreateLink redoPlayer = (CreateLink)currentChange().getRedoPlayer();
/* 9696 */       int itemId = getNextItemId(redoPlayer == null ? -1 : redoPlayer.getId());
/* 9697 */       String uuid = redoPlayer == null ? UUIDUtil.generateUUID() : redoPlayer.getUuid();
/* 9698 */       Link link = Link.create(getFolderById(folderId), itemId, uuid, name, ownerId, remoteId, null);
/* 9699 */       redoRecorder.setIdAndUuid(link.getId(), link.getUuid());
/* 9700 */       success = true;
/* 9701 */       return link;
/*      */     } finally {
/* 9703 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Collection<Comment> getComments(OperationContext octxt, int parentId, int offset, int length) throws ServiceException
/*      */   {
/* 9709 */     return getComments(octxt, parentId, offset, length, false);
/*      */   }
/*      */   
/*      */   Collection<Comment> getComments(OperationContext octxt, int parentId, int offset, int length, boolean fromDumpster) throws ServiceException
/*      */   {
/* 9714 */     boolean success = false;
/*      */     try {
/* 9716 */       beginTransaction("getComments", octxt, null);
/* 9717 */       MailItem parent = getItemById(parentId, MailItem.Type.UNKNOWN, fromDumpster);
/* 9718 */       return parent.getComments(SortBy.DATE_DESC, offset, length);
/*      */     } finally {
/* 9720 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public Collection<Comment> getComments(OperationContext octxt, String parentUuid, int offset, int length) throws ServiceException
/*      */   {
/* 9726 */     return getComments(octxt, parentUuid, offset, length, false);
/*      */   }
/*      */   
/*      */   Collection<Comment> getComments(OperationContext octxt, String parentUuid, int offset, int length, boolean fromDumpster) throws ServiceException
/*      */   {
/* 9731 */     boolean success = false;
/*      */     try {
/* 9733 */       beginTransaction("getComments", octxt, null);
/* 9734 */       MailItem parent = getItemByUuid(parentUuid, MailItem.Type.UNKNOWN, fromDumpster);
/* 9735 */       return parent.getComments(SortBy.DATE_DESC, offset, length);
/*      */     } finally {
/* 9737 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   public MailItem markMetadataChanged(OperationContext octxt, int itemId) throws ServiceException {
/* 9742 */     boolean success = false;
/*      */     try {
/* 9744 */       beginTransaction("markMetadataChanged", octxt, null);
/* 9745 */       MailItem item = getItemById(octxt, itemId, MailItem.Type.UNKNOWN);
/* 9746 */       item.markMetadataChanged();
/* 9747 */       success = true;
/* 9748 */       return item;
/*      */     } finally {
/* 9750 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   protected void migrateWikiFolders() throws ServiceException {
/* 9755 */     MigrateToDocuments migrate = new MigrateToDocuments();
/*      */     try {
/* 9757 */       migrate.handleMailbox(this);
/* 9758 */       ZimbraLog.mailbox.info("wiki folder migration finished");
/*      */     } catch (Exception e) {
/* 9760 */       ZimbraLog.mailbox.warn("wiki folder migration failed for " + getAccount().getName(), e);
/*      */     }
/*      */   }
/*      */   
/*      */   public String toString()
/*      */   {
/* 9766 */     return Objects.toStringHelper(this).add("id", this.mId).add("account", this.mData.accountId).add("lastItemId", this.mData.lastItemId).add("size", this.mData.size).toString();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean dumpsterEnabled()
/*      */   {
/* 9775 */     boolean enabled = true;
/*      */     try {
/* 9777 */       enabled = getAccount().isDumpsterEnabled();
/*      */     } catch (ServiceException e) {}
/* 9779 */     return enabled;
/*      */   }
/*      */   
/* 9782 */   public boolean useDumpsterForSpam() { return true; }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean isImmutableSystemFolder(int folderId)
/*      */   {
/* 9791 */     return false;
/*      */   }
/*      */   
/*      */   boolean isChildFolderPermitted(int folderId) {
/* 9795 */     return folderId != 4;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public boolean isNewItemIdValid(int id)
/*      */   {
/* 9802 */     return id < 1073741824;
/*      */   }
/*      */   
/*      */   public TypedIdList listItemsForSync(OperationContext octxt, int folderId, MailItem.Type type, long messageSyncStart) throws ServiceException {
/* 9806 */     if (folderId == -1) {
/* 9807 */       return new TypedIdList();
/*      */     }
/*      */     
/* 9810 */     boolean success = false;
/*      */     try {
/* 9812 */       beginTransaction("listMessageItemsforgivenDate", octxt);
/*      */       
/*      */ 
/* 9815 */       Folder folder = getFolderById(folderId);
/* 9816 */       TypedIdList ids = DbMailItem.listItems(folder, messageSyncStart, type, true, false);
/* 9817 */       success = true;
/* 9818 */       return ids;
/*      */     } finally {
/* 9820 */       endTransaction(success);
/*      */     }
/*      */   }
/*      */   
/*      */   /* Error */
/*      */   public Pair<List<Integer>, TypedIdList> getItemsChangedSince(OperationContext octxt, int sinceDate)
/*      */     throws ServiceException
/*      */   {
/*      */     // Byte code:
/*      */     //   0: aload_0
/*      */     //   1: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   4: iconst_0
/*      */     //   5: invokevirtual 217	com/zimbra/cs/mailbox/MailboxLock:lock	(Z)V
/*      */     //   8: iconst_0
/*      */     //   9: istore_3
/*      */     //   10: aload_0
/*      */     //   11: ldc_w 716
/*      */     //   14: aload_1
/*      */     //   15: invokevirtual 528	com/zimbra/cs/mailbox/Mailbox:beginReadTransaction	(Ljava/lang/String;Lcom/zimbra/cs/mailbox/OperationContext;)V
/*      */     //   18: aload_0
/*      */     //   19: iconst_1
/*      */     //   20: invokevirtual 717	com/zimbra/cs/mailbox/Mailbox:getAccessibleFolders	(S)Ljava/util/Set;
/*      */     //   23: invokestatic 718	com/zimbra/cs/mailbox/Folder:toId	(Ljava/util/Set;)Ljava/util/Set;
/*      */     //   26: astore 4
/*      */     //   28: aload_0
/*      */     //   29: getstatic 390	com/zimbra/cs/mailbox/MailItem$Type:UNKNOWN	Lcom/zimbra/cs/mailbox/MailItem$Type;
/*      */     //   32: iload_2
/*      */     //   33: aload 4
/*      */     //   35: invokestatic 2119	com/zimbra/cs/db/DbMailItem:getItemsChangedSinceDate	(Lcom/zimbra/cs/mailbox/Mailbox;Lcom/zimbra/cs/mailbox/MailItem$Type;ILjava/util/Set;)Lcom/zimbra/common/util/Pair;
/*      */     //   38: astore 5
/*      */     //   40: aload 5
/*      */     //   42: ifnonnull +21 -> 63
/*      */     //   45: aconst_null
/*      */     //   46: astore 6
/*      */     //   48: aload_0
/*      */     //   49: iload_3
/*      */     //   50: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   53: aload_0
/*      */     //   54: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   57: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   60: aload 6
/*      */     //   62: areturn
/*      */     //   63: iconst_1
/*      */     //   64: istore_3
/*      */     //   65: aload 5
/*      */     //   67: astore 6
/*      */     //   69: aload_0
/*      */     //   70: iload_3
/*      */     //   71: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   74: aload_0
/*      */     //   75: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   78: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   81: aload 6
/*      */     //   83: areturn
/*      */     //   84: astore 7
/*      */     //   86: aload_0
/*      */     //   87: iload_3
/*      */     //   88: invokevirtual 225	com/zimbra/cs/mailbox/Mailbox:endTransaction	(Z)V
/*      */     //   91: aload 7
/*      */     //   93: athrow
/*      */     //   94: astore 8
/*      */     //   96: aload_0
/*      */     //   97: getfield 40	com/zimbra/cs/mailbox/Mailbox:lock	Lcom/zimbra/cs/mailbox/MailboxLock;
/*      */     //   100: invokevirtual 49	com/zimbra/cs/mailbox/MailboxLock:release	()V
/*      */     //   103: aload 8
/*      */     //   105: athrow
/*      */     // Line number table:
/*      */     //   Java source line #9834	-> byte code offset #0
/*      */     //   Java source line #9837	-> byte code offset #8
/*      */     //   Java source line #9839	-> byte code offset #10
/*      */     //   Java source line #9841	-> byte code offset #18
/*      */     //   Java source line #9842	-> byte code offset #28
/*      */     //   Java source line #9844	-> byte code offset #40
/*      */     //   Java source line #9845	-> byte code offset #45
/*      */     //   Java source line #9850	-> byte code offset #48
/*      */     //   Java source line #9853	-> byte code offset #53
/*      */     //   Java source line #9847	-> byte code offset #63
/*      */     //   Java source line #9848	-> byte code offset #65
/*      */     //   Java source line #9850	-> byte code offset #69
/*      */     //   Java source line #9853	-> byte code offset #74
/*      */     //   Java source line #9850	-> byte code offset #84
/*      */     //   Java source line #9853	-> byte code offset #94
/*      */     // Local variable table:
/*      */     //   start	length	slot	name	signature
/*      */     //   0	106	0	this	Mailbox
/*      */     //   0	106	1	octxt	OperationContext
/*      */     //   0	106	2	sinceDate	int
/*      */     //   9	79	3	success	boolean
/*      */     //   26	8	4	folderIds	Set<Integer>
/*      */     //   38	28	5	dataList	Pair<List<Integer>, TypedIdList>
/*      */     //   46	36	6	localPair1	Pair<List<Integer>, TypedIdList>
/*      */     //   84	8	7	localObject1	Object
/*      */     //   94	10	8	localObject2	Object
/*      */     // Exception table:
/*      */     //   from	to	target	type
/*      */     //   10	48	84	finally
/*      */     //   63	69	84	finally
/*      */     //   84	86	84	finally
/*      */     //   8	53	94	finally
/*      */     //   63	74	94	finally
/*      */     //   84	96	94	finally
/*      */   }
/*      */   
/*      */   public void purgeExpiredIMAPDeletedMessages(long imapDeletedMessageLifeTime)
/*      */     throws ServiceException
/*      */   {
/* 9862 */     if (imapDeletedMessageLifeTime > 0L) {
/* 9863 */       ZimbraLog.purge.debug("Purging expired messages with IMAP \\Deleted flag");
/* 9864 */       Server server = getAccount().getServer();
/* 9865 */       int purgeBatchSize = server.getMailPurgeBatchSize();
/* 9866 */       long cutOff = (System.currentTimeMillis() - imapDeletedMessageLifeTime) / 1000L;
/* 9867 */       ZimbraLog.purge.debug("IMAP deleted message lifetime = %d, cutOff = %d", new Object[] { Long.valueOf(imapDeletedMessageLifeTime), Long.valueOf(cutOff) });
/* 9868 */       int batch = 0;
/* 9869 */       List<Integer> itemIdsWithDeletedFlag = null;
/*      */       do {
/* 9871 */         itemIdsWithDeletedFlag = DbMailItem.getIMAPDeletedItems(this, cutOff, purgeBatchSize);
/* 9872 */         if ((itemIdsWithDeletedFlag != null) && (itemIdsWithDeletedFlag.size() > 0)) {
/* 9873 */           batch++;
/* 9874 */           ZimbraLog.purge.debug("Batch %d - Found %d items with \\Deleted flags", new Object[] { Integer.valueOf(batch), Integer.valueOf(itemIdsWithDeletedFlag.size()) });
/* 9875 */           int[] itemIds = new int[itemIdsWithDeletedFlag.size()];
/* 9876 */           int pos = 0;
/* 9877 */           for (Integer integer : itemIdsWithDeletedFlag) {
/* 9878 */             itemIds[pos] = integer.intValue();
/* 9879 */             pos++;
/*      */           }
/* 9881 */           delete(null, itemIds, MailItem.Type.UNKNOWN, null);
/* 9882 */           ZimbraLog.purge.debug("Batch %d - Finished", new Object[] { Integer.valueOf(batch) });
/*      */         }
/* 9884 */       } while (itemIdsWithDeletedFlag.size() >= purgeBatchSize);
/* 9885 */       if ((batch == 0) && ((itemIdsWithDeletedFlag == null) || (itemIdsWithDeletedFlag.size() == 0))) {
/* 9886 */         ZimbraLog.purge.debug("Could not find any expired messages with IMAP \\Deleted flag");
/*      */       } else {
/* 9888 */         ZimbraLog.purge.debug("Purged total " + ((batch > 1 ? batch * purgeBatchSize : 0) + itemIdsWithDeletedFlag.size()) + " expired messages with IMAP \\Deleted flag");
/*      */       }
/* 9890 */       itemIdsWithDeletedFlag = null;
/*      */     } else {
/* 9892 */       ZimbraLog.purge.debug("IMAP deleted message life time is not set, so bypassed purging messages with IMAP \\Deleted flag");
/*      */     }
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailbox/Mailbox.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */